Android进程间通信(三):使用Messenger实现进程间通信
来源:互联网 发布:yii2连接多个数据库 编辑:程序博客网 时间:2024/06/04 17:50
一 Messenger介绍:
关于进程间的通信:
关于Android进程间的通信,在第一篇文章中我们通过传递Parcel对象,利用IBinder完成了进程间的通信,在第二篇文章 中我们通过在客户端创建一个aidl的文件,在服务端实例化由aapt生成的stub类的对象来完成了进程间的通信。今天我们来使用另一种更简洁的方法—Messenger来实现进程间的通信。
进程之间不能共享内存数据, 但是可以进行通信, 除了简单的Intent通信, 也可以使用Messenger, Messenger基于AIDL实现, 顺序执行, 不支持并发. 为了区分通信的始末, 我们暂定发送数据是客户端, 接收数据是服务端. 本文介绍Messenger的使用方式。
Messenger官方介绍:
Messenger–信使,类的继承关系:
public final class Messenger extends Object implements Parcelable //实现了Parcelable接口
定义:
1 Reference to a Handler, //一个Messenger关联了一个Handler2 which others can use to send messages to it. 3 This allows for the implementation of message-based communication across processes, //基于message的进程间通信4 by creating a Messenger pointing to a Handler in one process, 5 and handing that Messenger to another process.
解释为:Messenger引用了一个Handler对象,以便others能够向它发送消息(使用mMessenger.send(Message msg)方法)。该类允许跨进程间基于Message的通信(即两个进程间可以通过Message进行通信),在服务端使用Handler创建一个Messenger,客户端持有这个Messenger就可以与服务端通信了。
以前我们使用Handler+Message的方式进行通信,都是在同一个进程中,从线程持有一个主线程的Handler对象,并向主线程发送消息。
基于消息的进程间通信方式,如图所示:
可以看到,我们可以在客户端发送一个Message给服务端,在服务端的handler中会接收到客户端的消息,然后进行对应的处理,处理完成后,再将结果等数据封装成Message,发送给客户端,客户端的handler中会接收到处理的结果。
二 Handler+Messenger实现进程间的通信,一般使用按如下六个步骤:
(1)创建信使对象:
远程通过 serviceMessenger=new Messenger(new ServiceHandler()); 创建一个信使对象
(2)客户端使用bindlerService请求连接远程:
Intent intent =new Intent(MainActivity.this,MessengerService.class); bindService(intent, mConn, Context.BIND_AUTO_CREATE);
(3) 远程onBind方法返回一个bindler:
@Nullable @Override public IBinder onBind(Intent intent) { Log.i("TEST","MessengerService-->onBind()"); return serviceMessenger.getBinder(); }
(4) 客户端使用远程返回的bindler得到一个信使(即得到远程信使):
@Override public void onServiceConnected(ComponentName name, IBinder service){ Log.i("TEST","onServiceConnected()"); mServiceMessenger = new Messenger(service); mTvState.setText("连接成功!"); }
这里虽然是new了一个Messenger,但我们查看它的实现:
public Messenger(IBinder target) { mTarget = IMessenger.Stub.asInterface(target); }
发现它的mTarget是通过Aidl得到的,实际上就是远程创建的那个。
(5) 客户端可以使用这个远程信使对象向远程发送消息:
Message msgFromClient = Message.obtain(null, MSG_SUM); mServiceMessenger .send(msgFromClient);
这样远程服务端的Handler对象就能收到消息了,然后可以在其handlerMessage(Message msg)方法中进行处理。(该Handler对象就是第一步服务端创建Messenger时使用的参数ServiceHandler).
经过这5个步骤貌似只有客户端向服务端发送消息,这样的消息传递是单向的,那么如何实现双向传递呢?
(6)首先需要在第5步稍加修改,在mServiceMessenger .send(msgFromClient)前通过
msgFromClient.replyTo = mClientMessenger;
将自己的信使设置到消息中,这样服务端接收到消息时同时也得到了客户端的信使对象mClientMessenger了,然后服务端可以通过/得到客户端的信使对象,并向它发送消息 mClientMessenger= msg.replyTo; mClientMessenger.send(message);
即完成了从服务端向客户端发送消息的功能,这样客服端可以在自己的Handler对象的handlerMessage方法中接收服务端发送来的message进行处理。
双向通信宣告完成。下面来DEMO验证上面的实现双方通信的六个步骤。
三 DEMO实例
DEMO描述
DEMO分为服务端、客户端,实现一个计算三个整数的和。
客户端由普通的MainActivity充当,触发点击事件时,客户端会向服务端发送数据(DEMO中是发送三个整数);服务端由一个MessengerService充当,用于接收客户端发送过来的数据,并求和,然后将求和的结果返回到客户端。最后客户端接收服务端返回的结果,并展示在界面上。
服务端MessengerService.java代码如下:
/** * Created by Administrator on 2016/6/23. */public class MessengerService extends Service{ private static final int MSG_SUM = 0x110; private Messenger serviceMessenger; @Override public void onCreate() { super.onCreate(); Log.i("TEST","MessengerService-->onCreate()"); serviceMessenger=new Messenger(new ServiceHandler()); } @Nullable @Override public IBinder onBind(Intent intent) { Log.i("TEST","MessengerService-->onBind()"); return serviceMessenger.getBinder(); } @Override public boolean onUnbind(Intent intent) { Log.i("TEST","MessengerService-->onUnbind()"); return super.onUnbind(intent); } @Override public void onDestroy() { Log.i("TEST","MessengerService-->onDestroy()"); super.onDestroy(); } private static class ServiceHandler extends Handler{ @Override public void handleMessage(Message msgfromClient) { Message msgToClient = Message.obtain(msgfromClient);//返回给客户端的消息 switch (msgfromClient.what){ //msg 客户端传来的消息 case MSG_SUM: msgToClient.what = MSG_SUM; try{ //模拟耗时 Thread.sleep(2000); //msgToClient.arg2 = msgfromClient.arg1 + msgfromClient.arg2; //msgToClient.arg2 = msgfromClient.arg1 + msgfromClient.arg2+(int)(msgfromClient.obj); int arg1=Integer.parseInt(msgfromClient.getData().getString(Constans.ARG1)); int arg2=Integer.parseInt(msgfromClient.getData().getString(Constans.ARG2)); int arg3=Integer.parseInt(msgfromClient.getData().getString(Constans.ARG3)); msgToClient.arg1=arg1; msgToClient.arg2 = arg1 + arg2+arg3; msgfromClient.replyTo.send(msgToClient); } catch (InterruptedException e){ e.printStackTrace(); } catch (RemoteException e){ e.printStackTrace(); } break; } super.handleMessage(msgfromClient); } }}
同时在清单文件中注册该服务:
<service android:name=".MessengerService" android:process=".remote"></service>
客户端MainActivity 代码如下:
public class MainActivity extends AppCompatActivity { private static final int MSG_SUM = 0x110; //显示连接状态 private TextView mTvState; private Button mBtnAdd; private LinearLayout mLyContainer; private Messenger mServiceMessenger; private Messenger mClientMessenger; private int mA; private ServiceConnection mConn = new ServiceConnection(){ @Override public void onServiceConnected(ComponentName name, IBinder service){ Log.i("TEST","onServiceConnected()"); mServiceMessenger = new Messenger(service); mTvState.setText("连接成功!"); } @Override public void onServiceDisconnected(ComponentName name){ mServiceMessenger = null; mTvState.setText("disconnected!"); Log.i("TEST","onServiceDisconnected()"); } }; @Override protected void onCreate(Bundle savedInstanceState){ super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mClientMessenger = new Messenger(new ClientHandler()); mTvState = (TextView) findViewById(R.id.id_tv_callback); mTvState.setText("未连接"); mBtnAdd = (Button) findViewById(R.id.id_btn_add); mLyContainer = (LinearLayout) findViewById(R.id.id_ll_container); mBtnAdd.setOnClickListener(new View.OnClickListener(){ @Override public void onClick(View v){ if (mServiceMessenger==null){ Toast.makeText(MainActivity.this, "服务未连接或者被异常杀死!", Toast.LENGTH_SHORT).show(); return; } performCalculation(); } }); findViewById(R.id.connect).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { connectService(); } }); findViewById(R.id.disconnect).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { disconnectService(); } }); } private void performCalculation(){ try { int a = mA++; int b = (int) (Math.random() * 100); int c = (int) (Math.random() * 100); /**创建一个tv,添加到LinearLayout中*/ TextView tv = new TextView(MainActivity.this); tv.setText(a + " + " + b + " + " + c + " = caculating ..."); tv.setTextSize(20); tv.setId(a); mLyContainer.addView(tv); // Message msgFromClient = Message.obtain(null, MSG_SUM, a, b); // Message msgFromClient = Message.obtain(null, MSG_SUM, a, b,c); // 这种方式传递参数c会报错,Can't marshal non-Parcelable objects across processes. Message msgFromClient = Message.obtain(null, MSG_SUM); Bundle data=new Bundle();//Bundle实现了Parcelable接口 data.putString(Constans.ARG1,String.valueOf(a)); data.putString(Constans.ARG2,String.valueOf(b)); data.putString(Constans.ARG3,String.valueOf(c)); msgFromClient.setData(data); msgFromClient.replyTo = mClientMessenger; /**往服务端发送消息*/ mServiceMessenger.send(msgFromClient); } catch (RemoteException e){ e.printStackTrace(); } } @Override protected void onDestroy(){ super.onDestroy(); unbindService(mConn); } public void connectService(){ Intent intent =new Intent(MainActivity.this,MessengerService.class); bindService(intent, mConn, Context.BIND_AUTO_CREATE); } public void disconnectService(){ unbindService(mConn); mServiceMessenger=null; mTvState.setText("未连接"); } private class ClientHandler extends Handler{ @Override public void handleMessage(Message msgFromServer){ switch (msgFromServer.what){ case MSG_SUM: TextView tv = (TextView) mLyContainer.findViewById(msgFromServer.arg1); tv.setText(tv.getText() + "=>" + msgFromServer.arg2); break; } super.handleMessage(msgFromServer); } }}
方法执行顺序如下:
06-23 17:00:24.490 9869-9869/.remote I/TEST: MessengerService-->onCreate()06-23 17:00:24.490 9869-9869/.remote I/TEST: MessengerService-->onBind()06-23 17:00:24.500 9701-9701/com.troy.messengersample I/TEST: onServiceConnected()06-23 17:00:25.930 9869-9869/.remote I/TEST: MessengerService-->onUnbind()06-23 17:00:25.930 9869-9869/.remote I/TEST: MessengerService-->onDestroy()
Messenger实现进程通信的流程如下:
最后运行的结果如图:
DEMO总结:
(1)掌握使用Messenger实现进程间的通信;
(2)掌握Messenger通信之间使用Bundle或者Message传输数据;
(3)理解Messenger与Handler之间的关系;
(4)理解Messenger与Binder之间的关系;
学习资料致谢:
1 Android 基于Message的进程间通信 Messenger完全解析
http://blog.csdn.net/lmj623565791/article/details/47017485
2 Android 进程使用 Messenger 通信
http://www.wangchenlong.org/2016/05/17/1605/171-android-messenger/?hmsr=toutiao.io&utm_medium=toutiao.io&utm_source=toutiao.io
- Android进程间通信(三):使用Messenger实现进程间通信
- Android使用Messenger实现进程间通信
- Android进程间通信(3)-Messenger实现
- 使用Messenger实现进程间通信
- Android进程间通信之使用Messenger
- Android进程间通信之使用Messenger
- Android 进程间通信之使用Messenger
- Android进程间通信之使用Messenger
- Android Messenger 进程间通信
- Android 进程间通信 Messenger
- 进程间通信使用Messenger
- Android进程间通信(一):Messenger
- Android进程间通信(二)- Messenger
- Messenger(信使)进程间通信使用
- 使用Messenger实现进程间通信(IPC)
- 进程间通信----Messenger
- 进程间通信 Messenger
- 进程间通信Messenger
- SQL中如何取消数字前面的0 字母
- Python3从零学习(四)
- maven整合webservice(cxf)的时候可能会出现的问题
- elasticsearch-kibana 启用Index contains time-based events
- java中集合与数组之间的转化
- Android进程间通信(三):使用Messenger实现进程间通信
- 安卓提示信息管理
- tomcat 解析(三)-启动框架
- Web.config中的system.web system.webServer
- Android 实现切换主题皮肤功能(类似于众多app中的 夜间模式,主题包等)
- 剑指offer|链表中倒数第k个结点
- 如果实现python字典的只读, 考虑字典内容有list, dict的嵌套问题
- u-boot 移植到6410
- ios 队列简单理解