Android最常用来快进程通讯的手段是AIDL,这个大家都很熟悉了。今天我们来介绍另一个比AIDL使用起来更简单的跨进程方式Messenger,其实Messenger的内部实现就是用的AIDL,那么为什么我还要介绍他呢?主要是为了后面要介绍的AsyncChannel打个基础,好了,快点进入正题吧!
一.Messenger有什么用
Messenger就是用来发送消息的,核心方法只有一个send。从这个方法来看,显然Messenger是单向的,那如果要双向通信怎么办。其实很简单,两边分别创建一个Messenger对象,然后把创建的Messenger对象发给对方,这样就可以相互send消息了。
二.Messenger怎么用
假设张三和李四要用Messenger进行通信
张三首先这么操作:
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 1.张三创建Messenger对象
MessengerHandler messengerHandler = new MessengerHandler();
Messenger messenger = new Messenger(messengerHandler);
// 2.将Messenger对象通过Intent传递给李四
Intent intent = new Intent();
intent.setClassName("com.frezrik.lisi", "com.frezrik.lisi.MainActivity");
intent.putExtra("MESSENGER", messenger);
startActivity(intent);
}
public static class MessengerHandler extends Handler {
@Override
public void handleMessage(@NonNull Message msg) {
super.handleMessage(msg);
// 3.等待李四发送过来的消息
Log.w("zmzm", "zhangsan recv:" + msg.getData().getString("MSG"));
// 4.收到李四的消息后,张三回复消息
Bundle bundle = new Bundle();
bundle.putString("MSG", "zhangsan say hello");
Message message = Message.obtain();
message.setData(bundle);
try {
Log.w("zmzm", "zhangsan send hello");
msg.replyTo.send(message);
} catch (RemoteException e) {
e.printStackTrace();
}
}
}
}
李四的操作:
public class MainActivity extends AppCompatActivity {
private boolean mBound;
private Messenger mZsMessenger;
private Messenger mMessenger;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 1.李四拿到张三传过来的Messenger
Intent intent = getIntent();
mZsMessenger = intent.getParcelableExtra("MESSENGER");
if (mZsMessenger != null) {
mBound = true;
}
// 2.李四也创建一个Messenger,等下给张三来回复消息
MessengerHandler messengerHandler = new MessengerHandler();
mMessenger = new Messenger(messengerHandler);
}
@Override
protected void onDestroy() {
super.onDestroy();
mBound = false;
}
public void click(View view) {
if (mBound) {
// 3.李四发送消息给张三
try {
Bundle bundle = new Bundle();
bundle.putString("MSG", "lisi say hello");
Message message = Message.obtain();
message.replyTo = mMessenger; // 把李四创建的Messenger打包起来,等下一起发给张三
message.setData(bundle);
Log.d("zmzm", "lisi send hello");
mZsMessenger.send(message);
} catch (RemoteException e) {
e.printStackTrace();
}
}
}
public static class MessengerHandler extends Handler {
@Override
public void handleMessage(@NonNull Message msg) {
super.handleMessage(msg);
// 4.收到了张三回复的消息
Log.d("zmzm", "lisi recv:" + msg.getData().getString("MSG"));
}
}
}
二.Messenger原理
相关源码路径:
frameworks/base/core/java/android/os/IMessenger.aidl
frameworks/base/core/java/android/os/Messenger.java
frameworks/base/core/java/android/os/Handler.java
张三创建Messenger时,张三就是Messenger的服务端
//Messenger.java
private final IMessenger mTarget;
public Messenger(Handler target) {
mTarget = target.getIMessenger();
}
//Handler.java
final IMessenger getIMessenger() {
synchronized (mQueue) {
if (mMessenger != null) {
return mMessenger;
}
mMessenger = new MessengerImpl();
return mMessenger;
}
}
private final class MessengerImpl extends IMessenger.Stub {
public void send(Message msg) {
msg.sendingUid = Binder.getCallingUid();
Handler.this.sendMessage(msg);
}
}
看到这里就很清晰了,张三作为服务端实现了IMessenger.aidl的send方法
李四调用send方法
public void send(Message message) throws RemoteException {
mTarget.send(message);
}
这不就是AIDL调用吗,李四作为客户端拿到服务端对象mTarget,aidl调用send方法。Message的内容就被传到了服务端,实现了跨进程调用。后面的流程就都是在张三的进程里进行的了,Handler.this.sendMessage(msg)就是我们熟悉的handler了,msg通过enqueueMessage方法插入消息队列,Looper.loop()方法里dispatchMessage,最后通过handleMessage将消息送达