Home > Mobile >  How to send an initial message using ServiceConnection?
How to send an initial message using ServiceConnection?

Time:07-16

I have an android service, which is connected to a service connection. Upon initialization, I'd like to send a single String, for example "test message" to the Service connection. How would I do this?

This is my Service class:

public class ExampleService extends Service {
    private final IBinder iBinder = new Messenger(new IncomingHandler(this)).getBinder();

    @Override
    public IBinder onBind(Intent intent) {
        return iBinder;
    }
}

This is my ServiceConnection implementation:

private ServiceConnection myService = new ServiceConnection() {
    @Override
    public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
        Log.i("exampleService", "Binding Connect");
        messenger = new Messenger(iBinder);
    }

    @Override
    public void onServiceDisconnected(ComponentName componentName) {
        messenger = null;
    }
};

CodePudding user response:

The ServiceConnection monitors the state of the connection to the service, as opposed to communicating information to the service. To communicate with the service, you need to use the binder that is passed as an argument to the onServiceConnected(ComponentName name, IBinder binder) callback.

In your code sample, you are using a Messenger to perform communication instead of directly interacting with the binder. A Messenger is:

a simple wrapper around a Binder that is used to perform the communication

Sample code that does what you are asking:

public class MyService extends Service {
    // if there are a lot of options, use an enum; its not 2012 anymore and devices have 4GB  of memory
    public static final int MSG_HELLO = 1;


    private class IncomingHandler extends Handler {
        @Override
        public void handleMessage(Message message) {
            switch (message.what) {
                case MSG_HELLO:
                    final String stringMessage = (String) message.obj;
                    Toast.makeText(MyService.this.getApplicationContext(), "MyService: "   stringMessage, Toast.LENGTH_SHORT).show();
                default:
                    super.handleMessage(message);
            }
        }
    }

    final private Messenger messenger = new Messenger(new IncomingHandler());

    @Override
    public IBinder onBind(Intent intent) {
        return messenger.getBinder();
    }
}

public class MainActivity extends Activity {

    private static final String HELLO_MESSAGE = "hello originating from MyActivity";


    private Messenger messenger = null;

    private final ServiceConnection serviceConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
            messenger = new Messenger(iBinder);

            // send a HELLO message immediately when connected
            final Message message = Message.obtain(null, MyService.MSG_HELLO, HELLO_MESSAGE);

            try {
                messenger.send(message);
            } catch (RemoteException ignored) {
                // the service no longer exists (e.g. it crashed), nothing else to do
            }
        }

        @Override
        public void onServiceDisconnected(ComponentName componentName) {
            messenger = null;
        }
    };


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        final Intent intent = new Intent(this, MyService.class);
        bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        unbindService(serviceConnection);
    }
    
    // rest of implentation...
}

For a more detailed example of how to work with Messenger, see the Remote Messenger Service Sample.

A couple notes:

  1. If you are communicating with a local service (i.e. the service is in the same process as the activity), I recommend not using messenger as this will make things more complicated than necessary. Instead, you should create a subclass of Binder that has a method which returns the instance of the service. See the Local Service Sample for an example.
  2. Make sure every bindService(...) has a corresponding unbindService(...) and vice versa. For example, if you call bindService(...) in onCreate(), then call unbindService(...) in onDestroy().
  3. Regardless of whether the service is local or remote, be aware of memory leaks. IBinder instances may stay in memory beyond the lifecycle of the component that is containing it, potentially until the process is destroyed; this can cause a severe memory leak. If you subclass Binder inside of an Activity or Service class, then use a static inner class, as opposed to a non-static inner class which will have an implicit reference to the Service or Activity. If you need a reference to a context or lifecycle aware component, then use a WeakReference. The proper way to deal with this is outside the scope of this question. For related posts, see:
  • Related