Android: How to safely unbind a service
I have a service which is binded to application context like this:
getApplicationContext().bindService(
new Intent(this, ServiceUI.class),
serviceConnection,
Context.BIND_AUTO_CREATE
);
protected void onDestroy() {
super.onDestroy();
getApplicationContext().unbindService(serviceConnection);
}
For some reason, only sometimes the application context does not bind properly (I can't fix that part), however in onDestroy() I do unbindservice
which throws an error
java.lang.IllegalArgumentException: Service not registered: tools.cdevice.Devices$mainServiceConnection.
My question is: Is there a way to call unbindservice
safely or check if it is already bound to a service before unbinding it?
Thanks in advance.
Solution 1:
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(..)
Solution 2:
Here you can find a nice explanation and source codes how to work with bound services. In your case you should override methods (onServiceConnected
and onServiceDisconnected
) of ServiceConnection
object. Then you can just check mBound
variable in your code.
Solution 3:
Doing exactly what Andrey Novikov proposed didn't work for me. I simply replaced:
getApplicationContext().unbindService(serviceConnection);
With:
unbindService(serviceConnection);
Solution 4:
I found there are two issues. Attempting to bind more than once and also attempting to unbind more than once.
Solution:
public class ServiceConnectionManager implements ServiceConnection {
private final Context context;
private final Class<? extends Service> service;
private boolean attemptingToBind = false;
private boolean bound = false;
public ServiceConnectionManager(Context context, Class<? extends Service> service) {
this.context = context;
this.service = service;
}
public void bindToService() {
if (!attemptingToBind) {
attemptingToBind = true;
context.bindService(new Intent(context, service), this, Context.BIND_AUTO_CREATE);
}
}
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
attemptingToBind = false;
bound = true;
}
@Override
public void onServiceDisconnected(ComponentName componentName) {
bound = false;
}
public void unbindFromService() {
attemptingToBind = false;
if (bound) {
context.unbindService(this);
bound = false;
}
}
}
Solution 5:
Why do we get this error?
When you try to unregister a service which is not registered.
What are some common examples?
- Binding and Unbinding a service with different Context.
- calling
unBind(mserviceConnection)
more thanbind(...)
First point is self explanatory. Lets explore the second source of error more deeply. Debug your bind() and unbind() calls. If you see calls in these order then your application will end up getting the IllegalArgumentException
.
How can we avoid this?
There are two ways you should consider to bind and unbind a service in Activity. Android docs recommend that
- If you want to interact with a service only when the Activity is visible then
bindService() in
onStart()
and unbindService() inonStop()
Your Activity {
@Override
public void onStart(){
super.onStart();
bindService(intent, mConnection , Context.BIND_AUTO_CREATE);
}
@Override
public void onStop(){
super.onStop();
unbindService(mConnection);
}
}
- If you want to interact with a service even an Activity is in Background then
bindService() in
onCreate()
and unbindService() inonDestroy()
Your Activity {
@Override
public void onCreate(Bindle sis){
super.onCreate(sis);
....
bindService(intent, mConnection , Context.BIND_AUTO_CREATE);
}
@Override
public void onDestroy() {
super.onDestroy();
unbindService(mConnection);
}
}