赞
踩
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的总结》
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。