概述
说起 Android 进程间通信,大家第一时间的想法可能是编写AIDL文件,但是Android上面还有另外一种简单方便的实现方式:Messenger
,也就是这篇文章的主角。
实例
我们现在通过一个实例来介绍Messenger
的使用方法。
实例中用到了两个APK,MessengerClient和MessengerServer。
Server端
1 | public class MessengerService extends Service { |
AndroidManifest.xml1
2
3
4
5
6
7
8
9<service
android:name=".MessengerService"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="com.android.hq.messenger"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</service>
可以看到Server端代码很简单,就是一个 Service
,只需要去声明一个 Messenger
对象,然后 onBind
方法返回 mMessenger.getBinder()
。
Client端
1 | public class MainActivity extends AppCompatActivity { |
源码分析
看一下Messenger
的源码,首先看一下它的构造函数:1
2
3
4
5
6
7public Messenger(Handler target) {
mTarget = target.getIMessenger();
}
public Messenger(IBinder target) {
mTarget = IMessenger.Stub.asInterface(target);
}
我们先来分析第一个,看看这个getIMessenger()
是怎么实现的,在Handler.java类中,它是这么实现的:1
2
3
4
5
6
7
8
9final IMessenger getIMessenger() {
synchronized (mQueue) {
if (mMessenger != null) {
return mMessenger;
}
mMessenger = new MessengerImpl();
return mMessenger;
}
}
那么这个MessengerImpl()
类又是什么呢?1
2
3
4
5
6private final class MessengerImpl extends IMessenger.Stub {
public void send(Message msg) {
msg.sendingUid = Binder.getCallingUid();
Handler.this.sendMessage(msg);
}
}
咦!IMessenger.Stub
,似曾相识的感觉!是的,我们平时写aidl文件,就会生成一个IXXX.Stub
的类,那么是不是也有个IMessenger.aidl
的文件呢?哈,还真有,
frameworks/base/core/java/android/os/IMessenger.aidl:1
2
3
4
5
6
7
8package android.os;
import android.os.Message;
/** @hide */
oneway interface IMessenger {
void send(in Message msg);
}
到这里大家应该明白了,Messenger
和我们用aidl文件的方式实现进程间通信其实是异曲同工的,它也是依赖aidl文件生成的类,继承了IMessenger.Stub类,实现了send方法,send方法中参数会通过客户端传递过来,最终发送给handler进行处理。
其实在它的另一个构造函数中已经体现出来了:1
2
3public Messenger(IBinder target) {
mTarget = IMessenger.Stub.asInterface(target);
}
Messenger和AIDL区别
Messenger是以串行的方式处理客户端发来的消息,如果有大量的消息同时发送到服务端,服务端仍然只能一个一个的处理,如果有大量并发请求,Messenger就不太适用了。Messenger的作用主要是为了传递消息,很多时候我们可能需要跨进程调用服务端的方法,这种情形Messenger就无法做到了,这个时候可以直接使用AIDL来实现。
问题分析
在个别手机上会出现跨进程bindService
失败的问题,可能是个别定制rom默认禁止掉了跨进程bindService
这种方式,在原生系统里面是可以的。
或者是在手机管家里面设置允许应用后台运行即可。