The binder mechanism is the inter-process access mechanism throughout the Android system and is often used to access the service. Let's take a look at how the binder is used to access the service in combination with the code.
You can understand the service as a non-interface activity. It is a program running in the background. The so-called background is relative to the program that can be viewed, and the background program cannot directly interact with each other.
The binder is mainly used for inter-process communication, but can also be used for communication with the local service.
1. Let's first look at an example of communication with the local service.
package com.ckt.wangxin;import android.app.Service;import android.content.Intent;import android.os.Binder;import android.os.IBinder;import android.widget.Toast;/** * This is a service stub for both LocalBinderClient * and RemoteBinderClient * @author Wang Xin * @email springnap@163.com * */public class LocalService extends Service { @Override public IBinder onBind(Intent intent) { return new LocalBinder(); } public void sayHelloWorld(){ Toast.makeText(this.getApplicationContext(), "Hello World Local Service!", Toast.LENGTH_SHORT).show(); } public class LocalBinder extends Binder { LocalService getService() { // Return this instance of LocalService so clients can call public methods return LocalService.this; } } }
The Code of local servcie is as follows: The onbinder method returns the binder. The binder contains the Service handle. After the client obtains the handle, it can call the public method of servcie, this call method is the most common.
Client code
package com.ckt.wangxin;import android.app.Activity;import android.content.ComponentName;import android.content.Context;import android.content.Intent;import android.content.ServiceConnection;import android.os.Bundle;import android.os.IBinder;import android.util.Log;import com.ckt.wangxin.LocalService.LocalBinder;public class LocalServiceTestActivity extends Activity { static final String TAG = "LocalBinderTestActivity"; ServiceConnection mSc; /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); mSc = new ServiceConnection(){ @Override public void onServiceConnected(ComponentName name, IBinder service) { Log.d(TAG, "service connected"); LocalService ss = ((LocalBinder)service).getService(); ss.sayHelloWorld(); } @Override public void onServiceDisconnected(ComponentName name) { Log.d(TAG, "service disconnected"); } }; } @Override protected void onStart() { super.onStart(); Log.d(TAG, this.getApplicationContext().getPackageCodePath()); Intent service = new Intent(this.getApplicationContext(),LocalService.class); this.bindService(service, mSc, Context.BIND_AUTO_CREATE); } @Override protected void onStop() { super.onStop(); //must unbind the service otherwise the ServiceConnection will be leaked. this.unbindService(mSc); }}
Note that you need to unbind the service in onstop; otherwise, memory leakage may occur.
2. Let's look at the problem of communication with the service in another process (cross-process communication !).
How can I run servcie in another process? Configure attributes in manifest.
Android: Process = ": Remote" indicates that the service runs in different processes of the same application.
<?xml version="1.0" encoding="utf-8"?><manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.ckt.wangxin" android:versionCode="1" android:versionName="1.0" > <uses-sdk android:minSdkVersion="15" /> <application android:icon="@drawable/ic_launcher" android:label="@string/app_name" > <activity android:name=".LocalServiceTestActivity" android:label="@string/app_name" > <!-- <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> --> </activity> <service android:name=".LocalService"></service> <!-- android:process=":remote" specify this service run in another process in the same application. --> <service android:name=".RemoteService" android:process=":remote"></service> <activity android:name="RemoteServiceTestActivity"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application></manifest>
The client can use messenger to send messages to the service.
Client code:
package com.ckt.wangxin;import android.app.Activity;import android.content.ComponentName;import android.content.Context;import android.content.Intent;import android.content.ServiceConnection;import android.os.Bundle;import android.os.Handler;import android.os.IBinder;import android.os.Message;import android.os.Messenger;import android.os.RemoteException;import android.util.Log;import android.widget.Toast;public class RemoteServiceTestActivity extends Activity { static final String TAG = "RemoteServiceTestActivity"; ServiceConnection mSc; public static final int SAY_HELLO_TO_CLIENT = 0; /** * Handler of incoming messages from service. */ class IncomingHandler extends Handler { @Override public void handleMessage(Message msg) { switch (msg.what) { case SAY_HELLO_TO_CLIENT: Toast.makeText(RemoteServiceTestActivity.this.getApplicationContext(), "Hello World Remote Client!", Toast.LENGTH_SHORT).show(); break; default: super.handleMessage(msg); } } } Messenger messenger_reciever = new Messenger(new IncomingHandler()); /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); mSc = new ServiceConnection(){ @Override public void onServiceConnected(ComponentName name, IBinder service) { Log.d(TAG, "service connected"); Messenger messenger = new Messenger(service); Message msg = new Message(); msg.what = RemoteService.MSG_SAY_HELLO; msg.replyTo = messenger_reciever; try {messenger.send(msg);} catch (RemoteException e) {e.printStackTrace();} } @Override public void onServiceDisconnected(ComponentName name) { Log.d(TAG, "service disconnected"); } }; } @Override protected void onStart() { super.onStart(); Log.d(TAG, this.getApplicationContext().getPackageCodePath()); Intent service = new Intent(this.getApplicationContext(),RemoteService.class); this.bindService(service, mSc, Context.BIND_AUTO_CREATE); } @Override protected void onStop() { super.onStop(); //must unbind the service otherwise the ServiceConnection will be leaked. this.unbindService(mSc); }}
Obtain the binder sent from the service, which is used to build a messenger to send messages to the service.
Service Code:
package com.ckt.wangxin;import android.app.Service;import android.content.Intent;import android.os.Handler;import android.os.IBinder;import android.os.Message;import android.os.Messenger;import android.os.RemoteException;import android.widget.Toast;public class RemoteService extends Service { public static final int MSG_SAY_HELLO = 0; @Override public IBinder onBind(Intent intent) { return messager.getBinder(); } Handler IncomingHandler = new Handler() { @Override public void handleMessage(Message msg) { if(msg.replyTo != null){ Message msg_client = this.obtainMessage(); msg.what = RemoteServiceTestActivity.SAY_HELLO_TO_CLIENT; try {((Messenger)msg.replyTo).send(msg_client);} catch (RemoteException e) {// TODO Auto-generated catch blocke.printStackTrace();} } switch (msg.what) { case MSG_SAY_HELLO: Toast.makeText(RemoteService.this.getApplicationContext(), "Hello World Remote Service!", Toast.LENGTH_SHORT).show(); break; default: super.handleMessage(msg); } } }; Messenger messager = new Messenger (IncomingHandler);}
Build a messenger, including a handler, and then send the binder of the messenger to the client. The client can construct another messenger to communicate with the service through handler, and the message is processed in the handler.
Currently, the Service side responds to client messages in one way. Likewise, it can send messages in two ways to achieve two-way communication.
The demo source code can be downloaded here.