Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

binding to running Service (after finish() ) / callback Handler

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!
                    }
        }
}
like image 481
Johannes Staehlin Avatar asked Mar 16 '12 02:03

Johannes Staehlin


People also ask

How to start service from activity in Android?

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.

What is the use of onBind () in android?

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.

How to stop service Android?

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.


1 Answers

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.

like image 195
Johannes Staehlin Avatar answered Oct 20 '22 21:10

Johannes Staehlin