bind/unbind service example (android)
You can try using this code:
protected ServiceConnection mServerConn = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder binder) {
Log.d(LOG_TAG, "onServiceConnected");
}
@Override
public void onServiceDisconnected(ComponentName name) {
Log.d(LOG_TAG, "onServiceDisconnected");
}
}
public void start() {
// mContext is defined upper in code, I think it is not necessary to explain what is it
mContext.bindService(intent, mServerConn, Context.BIND_AUTO_CREATE);
mContext.startService(intent);
}
public void stop() {
mContext.stopService(new Intent(mContext, ServiceRemote.class));
mContext.unbindService(mServerConn);
}
Android: How to safely unbind a service
Try this:
boolean isBound = false;
...
isBound = getApplicationContext().bindService( new Intent(getApplicationContext(), ServiceUI.class), serviceConnection, Context.BIND_AUTO_CREATE );
...
if (isBound)
getApplicationContext().unbindService(serviceConnection);
Note:
You should use same context
for binding a service and unbinding a service. If you are binding Service with getApplicationContext()
so you should also use getApplicationContext.unbindService(..)
Why unbind Service onDestroy?
Activities need to handle configuration changes, such as when the screen is rotated, or the user changes locales, or the device enters night mode.
The default behavior of the foreground activity, when a configuration change occurs, is for it to be destroyed and recreated.
As a result, calling bindService()
on an Activity
is not a good idea. We want the binding to remain intact across the configuration change. Otherwise, our service will get destroyed and recreated, along with the activity (assuming that the activity has the one-and-only binding and nothing else started the service).
So, the recommended pattern is to call bindService()
on the Application
singleton. Then, you can pass your ServiceConnection
from the old activity instance to the new activity instance. Retained fragments work great for this, as you can then call unbindService()
in onDestroy()
of the fragment, so that when the activity is "permanently" destroyed (e.g., user presses BACK, you call finish()
), your binding can be released.
With all that as background, on to your specific concern.
First, you assume that a destroyed activity automatically unbinds from any services that it bound to via bindService()
called on that Activity
. It's possible that this happens, though I do not recall that being documented behavior, and it's the sort of thing that developers should not rely upon.
More importantly, in most cases, calling bindService()
on the Activity
is not the right approach. Otherwise, you get into the problems that I outlined above.
But, following the call-bindService()
-on-the-Application
pattern, I would not expect there ever to be some sort of automatic unbinding, because the Application
singleton is never destroyed. So, if you fail to call unbindService()
somewhere (e.g., in onDestroy()
of the retained fragment), you will leak your service.
Cleanly binding/unbinding to a Service in an Application
I solved this problem by counting the references to the service binding in the Application
. Every Activity
has to call acquireBinding()
in their onCreate()
methods and call releaseBinding()
in onDestroy()
. If the reference counter reaches zero the binding is released.
Here's an example:
class MyApp extends Application {
private final AtomicInteger refCount = new AtomicInteger();
private Binding binding;
@Override
public void onCreate() {
// create service binding here
}
public Binding acquireBinding() {
refCount.incrementAndGet();
return binding;
}
public void releaseBinding() {
if (refCount.get() == 0 || refCount.decrementAndGet() == 0) {
// release binding
}
}
}
// Base Activity for all other Activities
abstract class MyBaseActivity extend Activity {
protected MyApp app;
protected Binding binding;
@Override
public void onCreate(Bundle savedBundleState) {
super.onCreate(savedBundleState);
this.app = (MyApp) getApplication();
this.binding = this.app.acquireBinding();
}
@Override
public void onDestroy() {
super.onDestroy();
this.app.releaseBinding();
}
}
Should an Activity unbind from a started Foreground Service in onPause()?
Since setting up the ServiceConnection
takes some time, binding to the Service
in onResume()
may be way too late for your app to work smoothly. In addition to that, onPause()
will also be called e.g. when you show an AlertDialog
, so unbinding there means you'd have to "re-bind" as soon as the dialog is dismissed and - again - wait for the ServiceConnection
to be up and running.
The documentation on Bound Services states
You usually pair the binding and unbinding during matching bring-up
and tear-down moments of the client's lifecycle, as described in the
following examples:
- If you need to interact with the service only while your activity is visible, you should bind during onStart() and unbind during
onStop().- If you want your activity to receive responses even while it is stopped in the background, then you can bind during onCreate() and
unbind during onDestroy(). Beware that this implies that your activity
needs to use the service the entire time it's running (even in the
background), so if the service is in another process, then you
increase the weight of the process and it becomes more likely that the
system will kill it.
So in your case you can use onStart()
/ onStop()
When should I use unbindService(), and how should I use it properly to unbind from a remote service that is using an AIDL interface?
First, unless you actually need to make calls to this service across processes (that is, from other .apks, or you are using android:process to split up your own .apk into multiple processes for some reason), then I really recommend just dropping the use of aidl. It is more complexity for no gain. The "Local Service Sample" in the Service documentation shows how to do this: http://developer.android.com/reference/android/app/Service.html
Second, doing a bind at the same time as a start is a strong indication of some basic flaw in the design. Starting a service and binding to a service are semantically very different, so will be done at different places based on those different semantics. That is, if both are even done at all... in fact it is an unusual situation where you are using both start and bind with the same service.
In the class implementation of a service for doing music playback, it would use start when it is actively performing playback (so its process doesn't get killed by the system when the user is no longer actively interacting with the application's UI). Starting the service when the user has enters the UI is likely to cause pain because now the start/stopped state of the service is not clearly defined -- it could be started either because it is doing playback or because the user happens to have gone into the app's UI, and now when is the right time to stop it? This is going to be troublesome.
Now as far as when to unbind -- you just need to make sure you always match an unbindService() with a previous bindService(). From your snippets of code it looks like you are doing this, but there are strange things in it like mBound never being set. In fact if you are consistently binding in onStart() and unbinding in onStop(), you should never need to have an mBound to decide whether to unbind, because onStop() is always called after onStart().
So with the code you give here, it doesn't look like there is a problem. If you are getting exceptions, though, there clearly is so it may be elsewhere in your app. To help narrow the problem down, you can use this flag when you call bindService() to get additional information in the log when the failure happens: http://developer.android.com/reference/android/content/Context.html#BIND_DEBUG_UNBIND
Related Topics
Read the Package Name of an Android APK
How to Encrypt File from Sd Card Using Aes in Android
Font-Face on Android 4.0.X Doesn't Work
How to Scale a Website for Mobile Devices
How to Use Image as Button in Ionic
Background-Attachment:Fixed Not Working - Android Chrome (V40)
Android/Webkit Text-Overflow: Ellipsis Not Working
Android, How to Apply CSS into Webview
How to Check the Internet Connection in Android
Illegalargumentexception: Navigation Destination Xxx Is Unknown to This Navcontroller
When Should I Use the Assets as Opposed to Raw Resources in Android
How to Use Single Textwatcher for Multiple Edittexts
Calculating Distance Between Two Geographic Locations
Android How to Use Environment.Getexternalstoragedirectory()
How to Implement Filterable in Realmrecyclerviewadapter