我们先把通信机制图 画出来,然后再贴具体实现代码
下面,我们先看服务端代 码:
我们需要一个背后运行的service来 为其他应用提供工作,所以很快的我们就想到了 创建一个类继承Service,并实现其onBind(Intentintent)方法
public IBinderonBind (Intent intent) { returnnull; }
很明显,这里需要我 们返回一个IBinder的接口或者实现类,而这里我们的Message.getBinder()可以提供;所以需要我们创建Message对象;我们继续看Message的构造函数:
public Messenger(Handler target) {
mTarget = target.getIMessenger();}
需要一个handler处理器,那我们 就自己创建一个handler对象咯; 为了避免内存泄露,我们常创 建一个静态Handler类:
private static class MessengerHandler extends Handler { @Override public void handleMessage(Message msg) { super.handleMessage(msg); }}
其handlerMessage(Message msg)方法内部就进行接收到的数据处理。
完整的service代码:
public class MessengerService extends Service { private static final String TAG = "MessengerService"; private Messenger mClientMessenger; private static class MessengerHandler extends Handler { @Override public void handleMessage(Message msg) { Log.d(TAG, "YYYYYYYYYY"); switch (msg.what) { case IPCContants.MSG_FROM_CLIENT: Object object = msg.obj; if (!(object instanceof Bundle)){ break; } Bundle bundle = (Bundle) object; String clientMsg = bundle.getString("client"); Log.d(TAG, "YYYYYYYYYY receive msg from client: " + clientMsg); replayClient(msg); break; default: super.handleMessage(msg); break; } } } private static void replayClient(Message msg) { Messenger serviceMessage = msg.replyTo; Message message = new Message(); Bundle bundle = new Bundle(); bundle.putString("service", "hi, this is service msg"); message.obj = bundle; message.what = IPCContants.MSG_FROM_SERVICE; try { serviceMessage.send(message); } catch (RemoteException e) { e.printStackTrace(); } } @Nullable @Override public IBinder onBind(Intent intent) { MessengerHandler messengerHandler = new MessengerHandler(); mClientMessenger = new Messenger(messengerHandler); Log.d(TAG, "service is connection ..."); return mClientMessenger.getBinder(); } @Override public void onDestroy() { super.onDestroy(); }}
好、现在服务端代码写完了,但别忘了、我们需要把service给暴露外面应用调用,所以需要在manifest中进行配置,export=true 为允许其他应用调用;<intent-filter>为隐私启动的过滤配置
完整配置:
<service android:name=".ipcService.MessengerService" android:exported="true" > <intent-filter> <action android:name="com.example.hfs.alipayuidemo.ipcService.MessengerService"/> <category android:name="android.intent.category.DEFAULT"/> </intent-filter></service>
好了、现在我们来看客户端代码
客户需要主动调用,所以我们最平常的就是写acitivity然后放一个按钮,点击按钮进行与服务端的数据通信;当然最重要的事就是我们要与服务端的service进行建立连接才行啊,怎么连接呢?
我们刚看到服务端是通过service来提供服务的,所以我们要进行连接,就是启动服务端的service方法;所以用隐私启动来调用:
Intent intent = new Intent();intent.setComponent(new ComponentName("com.example.hfs.alipayuidemo","com.example.hfs.alipayuidemo.ipcService.MessengerService"));bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
注意、这里有个坑:就是安卓5.0以后需要用查询匹配的方式进行启动、具体添加下面的方法:
public Intent createExplicitFromImplicitIntent(Context context, Intent implicitIntent) { // Retrieve all services that can match the given intent PackageManager pm = context.getPackageManager(); List<ResolveInfo> resolveInfo = pm.queryIntentServices(implicitIntent, 0); // Make sure only one match was found if (resolveInfo == null || resolveInfo.size() != 1) { return null; } // Get component info and create ComponentName ResolveInfo serviceInfo = resolveInfo.get(0); String packageName = serviceInfo.serviceInfo.packageName; String className = serviceInfo.serviceInfo.name; ComponentName component = new ComponentName(packageName, className); // Create a new intent. Use the old one for extras and such reuse Intent explicitIntent = new Intent(implicitIntent); // Set the component to be explicit explicitIntent.setComponent(component); return explicitIntent;}
我们上面进行启动service时,有个mConnection参数,这个参数是干啥的呢?很明显、我们进行连接,需要一个serviceConnection对象;所以我们提前实例化此接口,暴露两方法:连接成功或失败
@Overridepublic void onServiceConnected(ComponentName name, IBinder service) {
}@Overridepublic void onServiceDisconnected(ComponentName name) {}
看到没,连接成功给我们返回了IBinder接口,前面我们写服务端时,连接成功在onBind()方法中,返回的就是这个IBinder接口;所以,我们现在只需要拿到这个IBinder接口来传输数据就可以了,这里我们先拿一个Messenger对象来存储:
mServiceMessenger = new Messenger(service);
好了 ,现在我们通过按钮来主动发送消息给服务端了:
先构造一个Message对象,然后把想传输的数据封装好放上面;再用之前保留的建立连接的Messenger来进行发送;
try { Message clientMessage = new Message(); clientMessage.what = IPCContants.MSG_FROM_CLIENT; Bundle clientBundle = new Bundle();//进程之间传递非基本数据类型的数据,需要使用Bundle,因为它实现了Parcelable clientBundle.putString("client","Hello,I am client user!"); clientMessage.obj = clientBundle; mServiceMessenger.send(clientMessage);} catch (RemoteException e) { e.printStackTrace();}
当然了,如果你想接受服务端的返回数据并进行处理,那同样的、我们需要创建一个Handler,然后用Messenger对象来包装好,并在发送消息时把自己作为回应给赋值上
clientMessage.replyTo = mClientMessenger;
回看服务端代码,我们可以发现、服务端进行回应数据的发送就是客户端这里创建好的Messenger对象:
MessengerHandler clientMessengerHandler = new MessengerHandler();mClientMessenger = new Messenger(clientMessengerHandler);
客户端完整代码:
public class MessengerActivity extends BaseActivity { private static final String TAG = "MessengerActivity"; private Messenger mServiceMessenger; private Messenger mClientMessenger; private static class MessengerHandler extends Handler { @Override public void handleMessage(Message msg) { switch (msg.what) { case IPCContants.MSG_FROM_SERVER: Object object = msg.obj; if (!(object instanceof Bundle)){ break; } Bundle bundle = (Bundle) object; String serviceMsg = bundle.getString("service"); LogUtil.d(TAG, "receive msg from service: " + serviceMsg); break; default: super.handleMessage(msg); break; } } } private ServiceConnection mConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { LogUtil.d(TAG, "service is connection ..."); mServiceMessenger = new Messenger(service); } @Override public void onServiceDisconnected(ComponentName name) { } }; @Override protected int layoutId() { return R.layout.activity_download; } @Override protected void initView() { super.initView(); Button button = (Button)findViewById(R.id.btn_download); button.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { clientSendMSg(); } }); } @Override protected void doOtherThing() { super.doOtherThing(); connectService(); } protected void connectService() { Intent intent = new Intent(); intent.setComponent(new ComponentName("com.example.hfs.alipayuidemo","com.example.hfs.alipayuidemo.ipcService.MessengerService")); intent = createExplicitFromImplicitIntent(this, intent); bindService(intent, mConnection, Context.BIND_AUTO_CREATE); MessengerHandler clientMessengerHandler = new MessengerHandler(); mClientMessenger = new Messenger(clientMessengerHandler); } private void clientSendMSg(){ try { Message clientMessage = new Message(); clientMessage.what = IPCContants.MSG_FROM_CLIENT; Bundle clientBundle = new Bundle();//进程之间传递非基本数据类型的数据,需要使用Bundle,因为它实现了Parcelable clientBundle.putString("client","Hello,I am client user!"); clientMessage.obj = clientBundle; clientMessage.replyTo = mClientMessenger;//通过clientMessage消息对象把客户端信使传递给服务端 mServiceMessenger.send(clientMessage); } catch (RemoteException e) { e.printStackTrace(); } } public Intent createExplicitFromImplicitIntent(Context context, Intent implicitIntent) { // Retrieve all services that can match the given intent PackageManager pm = context.getPackageManager(); List<ResolveInfo> resolveInfo = pm.queryIntentServices(implicitIntent, 0); // Make sure only one match was found if (resolveInfo == null || resolveInfo.size() != 1) { return null; } // Get component info and create ComponentName ResolveInfo serviceInfo = resolveInfo.get(0); String packageName = serviceInfo.serviceInfo.packageName; String className = serviceInfo.serviceInfo.name; ComponentName component = new ComponentName(packageName, className); // Create a new intent. Use the old one for extras and such reuse Intent explicitIntent = new Intent(implicitIntent); // Set the component to be explicit explicitIntent.setComponent(component); return explicitIntent; } @Override protected void onDestroy() { unbindService(mConnection); super.onDestroy(); }}
具体代码,可以到github下载:https://github.com/guiyichen/demoGavin