和 AIDL
不同的是,AIDL
必须同时应对若干个请求,这就必然会发生线程安全问题,Android 还为我们提供了另外一种无须考虑线程安全问题的 IPC 方法:Messenger
。
和 AIDL 同时应对若干进程的请求不同的是,Messenger
会将所有的请求排入队列当中,所以不会存在并发的情况,自然也就无须考虑线程安全问题了。
使用 Messenger
也很简单:
接收端:
Handler
,由这个 Handler
来接受来自发送端的信息Messenger
对象(Messenger
引用 Handler
对象)Messenger
创建 Binder
对象onBind
方法将 Binder
对象返回到发送端发送端:
IBinder
将 Messenger
实例化,然后调用 Messenger
对象的 send
方法将 Message
对象发送给接收端接收端:
public class MyService extends Service {
/**
* 第一步:创建一个 Handler
*/
private static class MyHandler extends Handler {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
Log.d("TTT", "发送端传递过来的消息是:" + msg.getData().getString("Message"));
}
}
@Override
public void onCreate() {
super.onCreate();
}
/**
* 第二步:创建一个 Messenger,该 Messenger 包含对 Handler 的引用
*/
private Messenger messenger = new Messenger(new MyHandler());
@Nullable
@Override
public IBinder onBind(Intent intent) {
//第三步:messenger 创建 IBinder 对象
//第四步:在 onBind 方法中奖 IBinder 对象返回
return messenger.getBinder();
}
}
发送端:
public class MainActivity extends Activity {
private static final int CLIENT_TO_SERVER = 100;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button bind = findViewById(R.id.get);
bind.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent();
intent.setComponent(new ComponentName("com.lixyz.messengerserver", "com.lixyz.messengerserver.MyService"));
bindService(intent, conn, BIND_AUTO_CREATE);
}
});
}
ServiceConnection conn = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
Messenger messenger = new Messenger(service);
Bundle bundle = new Bundle();
bundle.putString("Message", "这是给接收端的一封信");
Message message = Message.obtain();
message.what = CLIENT_TO_SERVER;
message.setData(bundle);
try {
messenger.send(message);
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
}
当然,不要忘记将接收端的 Service 暴露出去:
<service
android:name=".MyService"
android:exported="true" />
这样,一个简单的单项跨进程通信就完成了。
如果想要双向通信,也就是说,如果发送端也想要接受接收端发来的消息的话,可以设置 Message 对象的 replyTo 参数,将发送端 Messenger 传递过去,这样一来,接收端也就可以调用 Messenger 的 send 方法向发送端发送消息了。同样的,发送端也需要一个 Handler 对象来接收接收端回复过来的消息。
简单修改一下代码:
接收端:
private static class MyHandler extends Handler {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
Log.d("TTT", "发送端传递过来的消息是:" + msg.getData().getString("Message"));
Messenger messenger = msg.replyTo;
Bundle bundle = new Bundle();
bundle.putString("Message","这是接收端给发送端的回函");
Message message = Message.obtain();
message.setData(bundle);
try {
messenger.send(message);
} catch (RemoteException e) {
e.printStackTrace();
}
}
}
发送端:
ServiceConnection conn = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
Messenger messenger = new Messenger(service);
Bundle bundle = new Bundle();
bundle.putString("Message", "这是给接收端的一封信");
Message message = Message.obtain();
message.what = CLIENT_TO_SERVER;
message.setData(bundle);
//添加这一句,将 messenger 传递给 接收端
message.replyTo = messenger;
try {
messenger.send(message);
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
//再创建一个 Handler 来接收接收端回传过来的信息
private static class MyHandler extends Handler {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
Log.d("TTT", "接收端给发送端的回函是:" + msg.getData().getString("Message"));
}
}
至于如何区别信息,给 Message 设置 what 参数就可以啦
先从第一步 Messenger 的创建看起来:
/**
* 创建一个指定 Handler 的 Messenger。
* 通过这个 Messenger 发送的 Message 对象,都将在 Handler 呈现
* 就像直接调用 Handler 的 sendMessage 方法一样
*/
public Messenger(Handler target) {
mTarget = target.getIMessenger();
}
Messenger 的构造方法保存了 Handler 中 getIMessenger
方法的返回值,看一下这个方法:
final IMessenger getIMessenger() {
synchronized (mQueue) {
if (mMessenger != null) {
return mMessenger;
}
mMessenger = new MessengerImpl();
return mMessenger;
}
}
这个方法的逻辑也很简单,判断 mMessenger 是否为 null,如果为 null,则创建一个再返回,可以看到,Messenger 的构造方法中,mTarget 实际上保存的是一个 MessengerImpl
对象,看一下这个 MessengerImpl
private final class MessengerImpl extends IMessenger.Stub {
public void send(Message msg) {
msg.sendingUid = Binder.getCallingUid();
Handler.this.sendMessage(msg);
}
}
看到这里似乎有点儿熟悉,MessengerImpl 继承自 IMessenger.Stub
,还记不记得 AIDL 中的相关套路?没错儿,和 AIDL 一模一样,源码当中也存在一个 IMessenger.aidl
接口,位于:platform_frameworks_base\core\java\android\os
,其内容为:
package android.os;
import android.os.Message;
/** @hide */
oneway interface IMessenger {
void send(in Message msg);
}
也就是说,我们创建 Messenger 对象,实际上是获取了一个 IBinder 对象,而这个对象中实现了 send 方法。至此,接收端的第一步和第二步工作内容明确了,接着看第三步和第四步,更简单了:
/**
* 检索与该 Messenger 关联的 Handler 通信的 IBinder
*/
public IBinder getBinder() {
return mTarget.asBinder();
}
还记得 AIDL 文件由系统自动生成的同名 Java 文件不?里面的 asBinder 方法,实际上就是将自身返回了。
接收端的代码也就是这样了。
再看发送端这边,参数为 IBinder 的 Messenger 构造方法:
public Messenger(IBinder target) {
mTarget = IMessenger.Stub.asInterface(target);
}
是不是 AIDL 一样?接下来就是调用 send 方法了:
public void send(Message message) throws RemoteException {
mTarget.send(message);
}
还是和 AIDL 一样,其实就是调用了刚刚代理类中的的 send 方法把 Message 传进去。这里面的逻辑其实就是通过代理类中的 IBinder 对象来远程调用接收端中已经实现的 send 方法。
如果要双向通信,发送端通过 replyTo 参数将 Messenger 传递过去,这样接收端同样也可以利用这个 Messenger 来传递消息,接收端通过 Handler 来接收接收端回传的消息了。
首先说相同点:
不同点: