Again a question about LocalServices. How do I (re-)bind to an existing Service, after onDestroy()?
The Problem:
I'm binding to a Service and Starting the service from an Activity. I'm Posting runnable Objects to the Binder, for a callback (updating a progressbar) on the UI. When I close this Activity, the OS could end the lifecycle and Destroy the Activity, calling onDestroy(), right? I simulate this, calling finish() in onPause() method. So once I restart the Activity, how to I bind to the SAME Service again? I thought that Services are Singelton, but when I'm trying to re-bind, I get another binder reference. So binder.callbackHandler.post(binder.progressHandler);
still has the reference to the old binder/callback/progressHandler, not to my new one.
Even the Constructor of the Service is called again!
Is there any solution to have a progressbar, getting updated by callback objects from the service (working). Closing/onDestroy() the Activity. Come back, and continue the progressbar?
My code is quite large, but recreated the Szenario:
public class MyService extends Service {
private final LocalBinder binder = new LocalBinder();
public class LocalBinder extends Binder implements TestRunServiceBinder {
private Handler callbackHandler;
private ServiceStartActivity.RunOnServiceProgress onProgress;
@Override
public void setActivityCallbackHandler(Handler messageHandler) {
callbackHandler = messageHandler;
}
@Override
public void setServiceProgressHandler(RunOnServiceProgress runnable) {
onProgress = runnable;
}
public void doSomething(){
_doSomething();
};
private void _doSomething(){
while(...){
//do this a couple of times (could take up to 10min)
binder.callbackHandler.post(binder.progressHandler);
wait()
}
}
}
_
public class ServiceStartActivity{
private final Handler messageHandler = new Handler();
private ServiceConnection mTestServiceConnection = new ServiceConnection() {
@Override
public void onServiceDisconnected(ComponentName name) {
testRunBinder = null;
}
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
testRunBinder = (TestRunServiceBinder) service;
testRunBinder.setActivityCallbackHandler(messageHandler);
testRunBinder.setServiceProgressHandler(new RunOnServiceProgress());
}
};
@Override
protected void onStart() {
super.onStart();
// bind to the Service
final Intent serviceIntent = new Intent(ServiceStartActivity.this,
MyService.class);
getApplicationContext().bindService(serviceIntent,
mTestServiceConnection, Context.BIND_AUTO_CREATE);
}
@Override
protected void onStop() {
super.onStop();
getApplicationContext().unbindService(mTestServiceConnection);
}
public class RunOnServiceProgress implements Runnable {
@Override
public void run() {
//do something on the UI!
}
}
}
You can start a service from an activity or other application component by passing an Intent to startService() or startForegroundService() . The Android system calls the service's onStartCommand() method and passes it the Intent , which specifies which service to start.
To provide binding for a service, you must implement the onBind() callback method. This method returns an IBinder object that defines the programming interface that clients can use to interact with the service.
Stopping a service. You stop a service via the stopService() method. No matter how frequently you called the startService(intent) method, one call to the stopService() method stops the service. A service can terminate itself by calling the stopSelf() method.
I got it now. The solution is to explicit call startService(serviceIntent);
before you bind to the Service using getApplicationContext().bindService(serviceIntent,mTestServiceConnection, Context.BIND_AUTO_CREATE);
Reason: When you start a Service with bindService()
, it becomes a Bound Service an
runs only as long as another application component is bound to it.
If you start a Service with startService()
it can
can run in the background indefinitely,
So if you have e.g. a progessbar on the UI, and you want it to continue updating it, you should start your Service, and bind and undbind it in onResume() / onPause(). But be carfull: Since you started the Service manually, You should also stop it manually. The simplest way to do this is call stopSelf()
once the Service did it's work.
This soultion covers a proper binding from an Activity with e.g. an progresss bar to the same Service even after the activity is destroyed or after an orientation change.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With