文章目录
Android跨进程通信(一):AIDL使用教程1
Android跨进程通信(二):AIDL使用教程2
Android跨进程通信(三):Messenger使用教程
Android跨进程通信(四):AIDL源码解析
Android跨进程通信(五):Messenger源码解析
前面的文章讲述了如何通过AIDL来实现Android的跨进程通信,本篇文章来讲解如何使用Messenger来实现同样的功能。
介绍
Messenger是AIDL的封装,进程可以通过Messenger来实现通信。直接编写AIDL相当复杂,而Messenger大大简化了编写流程。
下面先介绍Messenger的基本使用方法。
准备工作
创建Messenger对象需要传入一个Handler,在这个Handler里对接收到的数据进行处理。
Handler handler = new Handler(){
@Override
public void handleMessage(@NonNull Message msg) {
...
}
}
Messenger messenger = new Messenger();
或者传入IBinder,这种方式是在客户端中实现的。
private class SensorConnection implements ServiceConnection{
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
mSensorMessenger = new Messenger(service);
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
}
发送数据方式如下。这里有两个地方容易弄混。
首先是message.replyTo = mMessenger,意思是在信封里说明谁是发送者。
其次是mRecvMessenger.send(message),A 要发送数据给 B,A用的是B的Messenger来发送。
Message message = Message.obtain();
//Bundle实现了序列化
Bundle bundle = new Bundle();
bundle.putString("name","PYJTLK");
message.setData(bundle);
message.replyTo = mMessenger;
mRecvMessenger.send(message);
而下面这种方式是错误的,因为是跨进程通信,发送的数据必须实现序列化。
Message message = Message.obtain();
//错误,因为String类没有实现序列化,应该把数据放入Bundle中,Bundle实现了序列化。
message.obj = new String("hello");
message.replyTo = mMessenger;
mRecvMessenger.send(message);
了解了Messenger的基本使用后,接下来就通过一个例子来讲述Messenger跨进程通信的完整流程。其中服务端提供温度传感器(模拟场景)服务,客户端绑定该服务,并通过Messenger来获取温度值。
服务端代码
首先创建一个传感器管理类,因为传感器在设备中是单例,所以这里使用单例模式。
public class SensorManager {
private static final int CMD_GET_TEMPERATURE = 0;
private static final int CMD_OPEN_SENSOR = 1;
private static final int CMD_SHUT_SENSOR = 2;
private static final String KEY_GET_TEMPERATURE_RESULT = "get result";
private static final String KEY_OPEN_SENSOR_RESULT = "open result";
private static final String KEY_SHUT_SENSOR_RESULT = "shut result";
private static SensorManager sSensorManager;
private SensorHandler mHandler;
private Messenger mMessenger;
private class SensorHandler extends Handler {
@Override
public void handleMessage(@NonNull Message msg) {
try {
Message message = Message.obtain();
//信封内说明谁是发送者
Messenger clientMessenger = msg.replyTo;
Bundle bundle = new Bundle();
message.setData(bundle);
String result;
switch (msg.what){
case CMD_GET_TEMPERATURE:
message.what = CMD_GET_TEMPERATURE;
//message.obj = new Double(...) 这种方法是不行的,因为Double类没有实现序列化,跨进程传输的类对象必须实现了序列化,比如Bundle
bundle.putDouble(KEY_GET_TEMPERATURE_RESULT,getTemperature());
message.replyTo = mMessenger;
//服务端发送数据,使用客户端的Messenger来发送
clientMessenger.send(message);
break;
case CMD_OPEN_SENSOR:
message.what = CMD_OPEN_SENSOR;
result = setTemperatureSensor(true) ? "open successfully" : "open failed";
//message.obj = new String("...") 这种方法是不行的,因为String类没有实现序列化,跨进程传输的类对象必须实现了序列化,比如Bundle
bundle.putString(KEY_OPEN_SENSOR_RESULT,result);
message.replyTo = mMessenger;
//服务端发送数据,使用客户端的Messenger来发送
clientMessenger.send(message);
break;
case CMD_SHUT_SENSOR:
message.what = CMD_SHUT_SENSOR;
result = setTemperatureSensor(true) ? "shut successfully" : "shut failed";
//message.obj = new String("...") 这种方法是不行的,因为String类没有实现序列化,跨进程传输的类对象必须实现了序列化,比如Bundle
bundle.putString(KEY_SHUT_SENSOR_RESULT,result);
message.replyTo = mMessenger;
//服务端发送数据,使用客户端的Messenger来发送
clientMessenger.send(message);
break;
}
} catch (RemoteException e) {
e.printStackTrace();
}
}
}
private SensorManager(){
mHandler = new SensorHandler();
mMessenger = new Messenger(mHandler);
}
//手机上的传感器属于单例,因此使用单例模式
public static SensorManager getInstance(){
synchronized (SensorManager.class){
if(sSensorManager == null){
sSensorManager = new SensorManager();
}
}
return sSensorManager;
}
public double getTemperature(){
try {
//假设获取温度信息是很耗时的任务
Thread.sleep(100);
double temperature = Math.random() * 100;
return temperature;
} catch (InterruptedException e) {
e.printStackTrace();
return -1;
}
}
public boolean setTemperatureSensor(boolean isOpen){
try {
//假设开关温度传感器是很耗时的操作
Thread.sleep(100);
return true;
} catch (InterruptedException e) {
e.printStackTrace();
return false;
}
}
public Messenger getMessenger(){
return mMessenger;
}
}
接下来创建一个SensorService类。注意,因为是跨进程通信,这个服务需要对外开放。
public class SensorService extends Service {
private static final String TAG = "SensorService";
@Override
public IBinder onBind(Intent intent) {
Log.d(TAG, "bind to sensor service");
return SensorManager.getInstance()
.getMessenger()
.getBinder();
}
}
在AndroidManifest添加此服务。
<service
android:name=".SensorService"
android:enabled="true"
android:exported="true"></service>
最后在服务端应用的MainActivity上启动此服务。
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Intent intent = new Intent(this,SensorService.class);
startService(intent);
}
}
至此,服务端的编写就完成了。下面来看看客户端的代码。
客户端代码
public class MainActivity extends AppCompatActivity {
private static final String TAG = "MainActivity";
private Button mGetButton;
private Button mOpenButton;
private Button mShutButton;
private TextView mTextView;
private SensorConnection mSensorConnection;
private ClientHandler mClientHandler;
private Messenger mClientMessenger;
private Messenger mSensorMessenger;
private class ClientHandler extends Handler{
@Override
public void handleMessage(@NonNull Message msg) {
Bundle bundle = msg.getData();
//如下是服务端的相关参数
//private static final int CMD_GET_TEMPERATURE = 0;
//private static final int CMD_OPEN_SENSOR = 1;
//private static final int CMD_SHUT_SENSOR = 2;
//private static final String KEY_GET_TEMPERATURE_RESULT = "get result";
//private static final String KEY_OPEN_SENSOR_RESULT = "open result";
//private static final String KEY_SHUT_SENSOR_RESULT = "shut result";
switch (msg.what){
//private static final int CMD_GET_TEMPERATURE = 0;
case 0:
double temperature = bundle.getDouble("get result");
MainActivity.this.runOnUiThread(new Runnable() {
@Override
public void run() {
mTextView.setText(temperature + "℃");
}
});
break;
//private static final int CMD_OPEN_SENSOR = 1;
case 1:
MainActivity.this.runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(MainActivity.this, "open successfully", Toast.LENGTH_SHORT).show();
}
});
break;
//private static final int CMD_SHUT_SENSOR = 2;
case 2:
MainActivity.this.runOnUiThread(new Runnable() {
@Override
public void run() {
MainActivity.this.runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(MainActivity.this, "shut successfully", Toast.LENGTH_SHORT).show();
}
});
}
});
break;
}
}
}
private class SensorConnection implements ServiceConnection{
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
mSensorMessenger = new Messenger(service);
Log.d(TAG, "connect successfully");
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mTextView = findViewById(R.id.text);
mGetButton = findViewById(R.id.button_get);
mOpenButton = findViewById(R.id.button_open);
mShutButton = findViewById(R.id.button_shut);
mGetButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
try {
Message message = Message.obtain();
//信封内告诉收件人谁是发送者
message.replyTo = mClientMessenger;
message.what = 0;
mSensorMessenger.send(message);
} catch (RemoteException e) {
e.printStackTrace();
}
}
});
mOpenButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
try {
Message message = Message.obtain();
//信封内告诉收件人谁是发送者
message.replyTo = mClientMessenger;
message.what = 1;
mSensorMessenger.send(message);
} catch (RemoteException e) {
e.printStackTrace();
}
}
});
mShutButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
try {
Message message = Message.obtain();
//信封内告诉收件人谁是发送者
message.replyTo = mClientMessenger;
message.what = 2;
//客户端发送数据,使用服务端的Messenger来完成
mSensorMessenger.send(message);
} catch (RemoteException e) {
e.printStackTrace();
}
}
});
bindSensorService();
}
private void bindSensorService(){
mSensorConnection = new SensorConnection();
mClientHandler = new ClientHandler();
mClientMessenger = new Messenger(mClientHandler);
//Intent intent = new Intent("com.pyjtlk.sensorserver.SensorService"); //这是隐式绑定Service,Android5.0开始就不支持了
Intent intent = new Intent();
intent.setComponent(new ComponentName("com.pyjtlk.sensorserver","com.pyjtlk.sensorserver.SensorService"));
bindService(intent,mSensorConnection,BIND_AUTO_CREATE);
}
}
比较与思考
Messenger和AIDL都可以实现跨进程通信,那么它们的区别在哪呢?
首先,从上面的例子我们知道Messenger的数据是放在Bundle里的,而Bundle只适合少量基本类型数据的传输。相反,AIDL可以传输序列化的对象。
其次,Messenger的数据收发是异步的,而AIDL是同步的。
因为是跨进程\跨应用通信,我们并不能保证本方在发送数据时对方还活着。因此,需要引入一些机制来确定双方是否已经断开了,比如超时等待机制。
最后
服务端和客户端都放在Gitee代码仓库里了。下一篇文章我们将通过源码来分析AIDL的原理。
对Messenger源码感兴趣的朋友可以看这篇文章。
参考文章
《Android Messenger使用及分析》
《android Messenger》
《关于Android Messenger的总结》