Android 使用Messenger实现跨进程之间通信
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android 使用Messenger实现跨进程之间通信相关的知识,希望对你有一定的参考价值。
参考技术A 以前讲到跨进程通信,我们总是第一时间想到AIDL(android接口定义语言),实际上,使用Messenger在很多情况下是比使用AIDL简单得多的。
大家看到Messenger可能会很轻易的联想到Message,然后很自然的进一步联想到Handler——没错,Messenger的核心其实就是Message以及Handler来进行线程间的通信。
以下是如何使用Messenger的步骤:
综上六步就能完成客户端与Service的跨进程双向通信过程:
客户端 -> Service -> 客户端
简单的例子(客户端向服务器端发送消息,服务器接收):
服务端主要是返给客户端一个IBinder实例,以供服务端构造Messenger,并且处理客户端发送过来的Message。当然,不要忘了要在Manifests文件里面注册.
客户端就主要是发起与服务端的绑定,以及通过onServiceConnected()方法来过去服务端返回来的IBinder,借此构造Messenger,从而可以通过发送Message的方式与服务端进行交互。
服务器接收消息后回复消息给客户端
客户端修改:
客户端需要添加一个handler用于接收消息
服务端修改:
在服务端的handler获取客户端发送的msg.replyTo
跨进程通信之Messenger
1.简介
Messenger,顾名思义即为信使,通过它可以在不同进程中传递Message对象,通过在Message中放入我们需要的入局,就可以轻松实现数据的跨进程传递了。Messenger是一种轻量级的IPC方案,其底层实现是AIDL。
Messenger的使用方法很简单,它对AIDL进程了封装,并且由于它一次只处理一个请求,因此在服务端我们不需要考虑同步的问题。
2.实现跨进程通信
1)服务端进程
首先我们需要在服务端创建一个Service来处理客户端的连接请求,同时创建一个Handler并通过它来创建一个Messenger对象。然后在Service的onBind方法中返回这Messenger对象底层的Binder即可。
2)客户端进程
客户端进程中,首先需要绑定服务端的Service,绑定成功后用服务端返回的IBinder对象创建一个Messenger,并通过这个Messenger对象向服务端发送Message。此外,如果需要服务端响应客户端,我们就需要像服务端那样创建一个Handler并创建一个新的Messenger,并把这个Messenger对象通过Message的replyTo参数传递给服务器,服务器就可以通过这个replyTo参数回应客户端了。
Messenger由于是在AIDL上进行了封装,其使用过程相对比较简单,下面的示例实现了客户端发送消息给服务端,服务端会根据客户端发送的消息予以回复并将回复的结果显示在客户端上。
3)下面直接贴上client和service的代码,最后附上运行结果。
Client:package com.pignet.messengerdemo2;import android.content.ComponentName;import android.content.Context;import android.content.Intent;import android.content.ServiceConnection;import android.os.Handler;import android.os.IBinder;import android.os.Message;import android.os.Messenger;import android.os.RemoteException;import android.support.v7.app.AppCompatActivity;import android.os.Bundle;import android.view.View;import android.widget.Button;import android.widget.EditText;import android.widget.TextView;import android.widget.Toast;public class MainActivity extends AppCompatActivity { private static TextView tvMsgFromService; Button btnSend; EditText etClient; private Messenger mService; private Messenger mGetReplyFromService =new Messenger(new MessengerHandler()); private static class MessengerHandler extends Handler{ @Override public void handleMessage(Message msg) { switch (msg.what){ case 1: tvMsgFromService.setText(msg.getData().getString("reply")); break; } super.handleMessage(msg); } } private ServiceConnection mConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { mService=new Messenger(service); } @Override public void onServiceDisconnected(ComponentName name) { } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); btnSend= (Button) findViewById(R.id.btn_send); etClient= (EditText) findViewById(R.id.et_client); tvMsgFromService = (TextView) findViewById(R.id.tv_msg_from_service); Intent intent= new Intent(MainActivity.this,MessengerService.class); bindService(intent,mConnection, Context.BIND_AUTO_CREATE); btnSend.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { String msgFromClient; Message msg = Message.obtain(null,0); Bundle data = new Bundle(); if((msgFromClient=String.valueOf(etClient.getText()))==null){ Toast.makeText(MainActivity.this,"The Message is null",Toast.LENGTH_SHORT).show(); }else{ data.putString("msg", msgFromClient); msg.setData(data); msg.replyTo= mGetReplyFromService; try { mService.send(msg); } catch (RemoteException e) { e.printStackTrace(); } } } }); } @Override protected void onDestroy() { unbindService(mConnection); super.onDestroy(); } }
Service:
package com.pignet.messengerdemo2;import android.app.Service;import android.content.Intent;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.support.annotation.Nullable;import android.util.Log;/** * Created by DB on 2017/7/2. */public class MessengerService extends Service { private static final String TAG="MessengerService"; private static class MessengerHandler extends Handler{ @Override public void handleMessage(Message msg) { switch (msg.what){ case 0: Log.i(TAG, "receive msg from client: "+msg.getData().getString("msg")); Messenger mService = msg.replyTo; Message replyMessage = Message.obtain(null,1); Bundle bundle = new Bundle(); bundle.putString("reply","您的信息"+msg.getData().getString("msg")+"已收到,稍后会有回复"); replyMessage.setData(bundle); try{ mService.send(replyMessage); } catch (RemoteException e) { e.printStackTrace(); } } super.handleMessage(msg); } } private final Messenger mMessenger = new Messenger(new MessengerHandler()); @Nullable @Override public IBinder onBind(Intent intent) { return mMessenger.getBinder(); } }
这里为了模拟不同应用间的跨进程通信,将Service类运行在了与Client不同的进程中,这样就可以实现和不同应用间通信一样的效果。
所以我们需要在manifests文件中加入:
<service android:name=".MessengerService" android:process=":romote"></service>
运行结果如下
3.Messenger源码浅析:
进入到Messenger源码后,查看它的结构
Messenger类有两个构造函数,分别是可以用Handler和IBinder实现,这也是我们之前实现跨进程中通信中实例化Messenger类中已经用到的两种构造函数。
public Messenger(Handler target) { mTarget = target.getIMessenger(); }
public Messenger(IBinder target) { mTarget = IMessenger.Stub.asInterface(target); }
因为之前提到过Messenger的底层实现是AIDL,所以这边我看这个IMessage和那个IBookManager有的类似,点开后发现确实如此
public interface IMessenger extends android.os.IInterface { /** Local-side IPC implementation stub class. */ public static abstract class Stub extends android.os.Binder implements android.os.IMessenger { private static final java.lang.String DESCRIPTOR = "android.os.IMessenger"; public Stub() { this.attachInterface(this, DESCRIPTOR); } public static android.os.IMessenger asInterface(...} public android.os.IBinder asBinder() { return this; } @Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException {...} private static class Proxy implements android.os.IMessenger {...} public void send(android.os.Message msg) throws android.os.RemoteException; }
之前我们为BookManager类定义的方法是一个addBook和getBookList,而这边我们发现Messenger对AIDL的封装中加入的是一个send方法。
那这个方法是在哪里实现的呢。
private final class MessengerImpl extends IMessenger.Stub { public void send(Message msg) { msg.sendingUid = Binder.getCallingUid(); Handler.this.sendMessage(msg); } }
它是在Handler类中的MessengerImpl方法中得到实现的,这也就可以解释我们发送的message可以在Handler的handleMessage中出现了。
最后我们再回到Messenger类中看看Messenger的另一个重要方法:
public void send(Message message) throws RemoteException { mTarget.send(message); }
这里我们就可以串联起来了,Messenger类通过传入Handler或是IBinder来获得IMessenger的实例,然后调用send方法实际是在远程调用IMessenger的send方法。
这里我们就差不多把Messenger的机制理清了。
最后附上刚才实现的例子的一个简图:
以上是关于Android 使用Messenger实现跨进程之间通信的主要内容,如果未能解决你的问题,请参考以下文章
Android基础——Messenger在跨进程通信中的使用
android 史上最简单易懂的跨进程通讯(Messenger)!
Android 进阶——轻量级跨进程传递Message利器Messenger详解
Android 进阶——轻量级跨进程传递Message利器Messenger详解