安卓进程通讯之messenger
想法:
通常,在一个进程中,如果需要做一些耗时操作,需要在工作线程中完成,但是如何把结果返还给主线程,有一种做法是主线程把关联了自己looper的handle给工作线程,工作线程耗时任务完成后利用handle发消息给主线程,用这个方法来完成线程间通讯。
work thread代码如下
public void doInWorkThread(final Handler handler){
new Thread(){
public void run() {
try {
//线程休眠10秒,模拟耗时操作
Thread.currentThread().sleep(10000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
handler.sendEmptyMessage(0);//耗时操作完成后,发消息给主线程
};
}.start();
}
主线程代码如下
private Handler handler=new Handler(){
public void handleMessage(android.os.Message msg) {
int what=msg.what;
if(what==0){
Toast.makeText(MainActivity.this, "work thread send message", Toast.LENGTH_SHORT).show();
}
};
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
new WorkThread().doInWorkThread(handler);
}
根据这个消息模型联想跨进程通讯能否也采用类似的发消息的方式呢?
当然有了,安卓给我们提供了一个封装好的类,使用这个类可以像handler一样跨进程发消息,这个类就是今天要说的Messenger
首先,查看该类的重要方法
public Messenger(Handler target) {
mTarget = target.getIMessenger();
}
通过handler创建Messenger对象,创建的对象必然关联handler所关联的looper
public IBinder getBinder() {
return mTarget.asBinder();
}
从Messenger对象中获取Binder,Binder用于跨进程通讯的,获取到的Binder可以给别的进程
public Messenger(IBinder target) {
mTarget = IMessenger.Stub.asInterface(target);
}
利用Ibinder创建Messenger对象
public void send(Message message) throws RemoteException {
mTarget.send(message);
}
利用Messenger发消息
看完以上4个Messenger方法,可以分析出Messenger跨进程发消息的流程
1,进程A创建关联自己looper的handler,使用handler创建Messenger;
2,利用Messenger生成IBinder,并把IBinder给进程B;
3,进程B拿到IBinder后,使用public Messenger(IBinder target)方法创建关联了A进程handler的Messenger;
4,进程B使用messenger对象的send方法给进程A发消息
A 进程(消息接受)代码如下
//创建handler 默认关联主线程loop
private Handler handler=new Handler(){
public void handleMessage(android.os.Message msg) {
int what=msg.what;
if(what==2222){
Log.i("TAG", "process A receive message from process B,process id is "+Process.myPid());
}
};
};
//使用handler来创建messenger
private Messenger messenger=new Messenger(handler);
@Override
public IBinder onBind(Intent intent) {
//使用messenger生成IBinder
return messenger.getBinder();
}
B进程 (消息发送)代码如下
private Messenger aMessenger;
private ServiceConnection connection=new ServiceConnection() {
@Override
public void onServiceDisconnected(ComponentName name) {
}
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
//利用A进程传来的 IBinder创建 Messenger
aMessenger=new Messenger(service);
Message message=Message.obtain(null, 2222);
try {
aMessenger.send(message);//给A进程发送消息
Log.i("TAG", "A process send message to B process,A process id is "+Process.myPid());
} catch (RemoteException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
};
-
运行结果
- process A receive message from process B,process id is 1808
-
A process send message to B process,A process id is 1795
根据结果可以看到两个进程确实通过Messenger传递了消息,那么现在有这么一个问题,在A进程接受到消息后,怎么给B进程回应。
在message中有一个共有属性replyTo,该属性的类型是Messenger,那么可以在B进程中创建关联了自己handler的Messenger对象,并且把该对象附加到发送给A进程的message 上,在A进程拿到message后,取出messenger就可以给B进程发消息了,
相关代码如下:
B进程
//创建关联B进程主线程的handler
private Handler handler=new Handler(){
public void handleMessage(Message msg) {
int what=msg.what;
if(what==3333){
Log.i("TAG", "process B receive process A reply");
}
};
};
//创建messenger对象
private Messenger bMessenger=new Messenger(handler);
Message message=Message.obtain(null, 2222);
message.replyTo=bMessenger;//附加messenger到message上
aMessenger.send(message);//给A进程发送消息
A进程
Messenger bMessenger = msg.replyTo;//拿到B的messenger
Message message=Message.obtain(null, 3333);
bMessenger.send(message);//发消息给B进程