进程间通信----Messenger
2015-08-24 22:02
309 查看
在上次,我写到了利用aidl来进行进程间通信的方式,并且满足了基本需求,然后,使用aidl方式进行进程间通信始终比较麻烦,需要写aidl文件等等,那么是否有比较简单的通信方式呢,是有的那就是Messenger
本篇的内容主要是参考着
/article/1580249.html;
【张鸿洋的博客】
来完成的,我只是在看了之后进行了自己的编写测试,并且针对我在项目中需要传递自定义对象扩展了一下
使用Messenger进行通信的方式要比aidl写起来方便的多,这种方式大概的流程为:
这种方式可以做到双向通信
那么下面就是代码了,首先是服务端:我自己的测试的项目在另一台电脑上,所以就拿借鉴的博主的代码来了,其实
我自己写的是差不多的
客户端代码结束之后就是服务端的代码
在上面的例子中,是传递了基本类型的参数,而我们实际使用中则很多都会需要用到传递自定义类型,这种时候只需要这么做就行了
通过上面的方式可以方便的进行进程间的通讯
那么,为什么通过这种方式可以进行进程间通讯呢?这一点在我解读的文章中也有描述
之前我了解过aidl的进程通讯方式,在aidl的通讯方式可以发现与这里非常相似
1、bindService的方式
2、ServiceConnection的使用
3、aidl接口的对象获取,其实可以发现这里也是一样的
这里调用的通讯方式为Messenger mService = new Messenger(service);
而aidl的接口对象获取方式为:ICalcAIDL mCalcAidl = ICalcAIDL.Stub.asInterface(service);
表面上看起来好像有点不同,但是,如果我们去看Messenger的构造器
这里返回的mTarget对象为
private final IMessenger mTarget;
跟aidl客户端的方式一模一样,在调用通讯方法send(Message message)我们再去看
那么客户端我们发现了是一样的,再去看服务端呢?
在服务端我们的代码是
而aidl的通讯方式是
然后
那么,现在的Messenger方式又是怎样的呢
我们首先来看Messenger的构造器,来看看这这里面做了什么
这个IMessenger,其实是依赖一个aidl生成的类
于:
这样,在服务端就只差一个东西了,就是实现了IMessenger.Stub的对象,这个对象我们去哪里找?
然后我们去看
这里的target.getMessenger()方法,我们进去看一下,可以看到
这样一来,需要的要素就都齐了,按照现在的代码来推测的话,不难推测出
这里调用了asBinder()方法,再进去看
这里这个asBinder方法的源码是aidl文件在gen路径下生成的类里面可以看到的,如果读者想看的话,可以在aidl的例子中查看,就可以看到
那么Messenger配合Handler的进程间通信的原理到这里就分析结束了,从这个看来的话,其实我们完全也可以自己写一个类似于Messenger的对象用来进行进程间通信,并且利用Message可以传递数据的特性来进行数据的传递,可以说还是非常方便的
本篇的内容主要是参考着
/article/1580249.html;
【张鸿洋的博客】
来完成的,我只是在看了之后进行了自己的编写测试,并且针对我在项目中需要传递自定义对象扩展了一下
使用Messenger进行通信的方式要比aidl写起来方便的多,这种方式大概的流程为:
这种方式可以做到双向通信
那么下面就是代码了,首先是服务端:我自己的测试的项目在另一台电脑上,所以就拿借鉴的博主的代码来了,其实
我自己写的是差不多的
package com.example.aidlClientdemo; import android.app.Service; import android.content.Intent; import android.os.Handler; import android.os.HandlerThread; import android.os.IBinder; import android.os.Message; import android.os.Messenger; import android.os.RemoteException; public class ProcessCommonicationService extends Service{ private static final int MSG_SUM = 0x110; HandlerThread handlerThread = new HandlerThread("myHandlerThread"); //这里在handler构造器内传入handlerThread的Lopper,可以让handleMessage在handlerThread的线程内队列执行 private Messenger mMessenger = new Messenger(new Handler(handlerThread.getLooper()) { @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; msgfromClient.replyTo.send(msgToClient); } catch (InterruptedException e) { e.printStackTrace(); } catch (RemoteException e) { e.printStackTrace(); } break; } super.handleMessage(msgfromClient); } }); @Override public void onCreate() { super.onCreate(); //使用handlerThread可以进行队列执行 handlerThread.start(); } @Override public IBinder onBind(Intent intent) { return mMessenger.getBinder(); } }
客户端代码结束之后就是服务端的代码
package com.imooc.messenger_client; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; import android.os.Bundle; import android.os.Handler; import android.os.IBinder; import android.os.Message; import android.os.Messenger; import android.os.RemoteException; import android.support.v7.app.AppCompatActivity; import android.util.Log; import android.view.View; import android.widget.Button; import android.widget.LinearLayout; import android.widget.TextView; public class MainActivity extends AppCompatActivity { private static final String TAG = "MainActivity"; private static final int MSG_SUM = 0x110; private Button mBtnAdd; private LinearLayout mLyContainer; //显示连接状态 private TextView mTvState; private Messenger mService; private boolean isConn; private Messenger mMessenger = new Messenger(new 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); } }); private ServiceConnection mConn = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { mService = new Messenger(service); isConn = true; mTvState.setText("connected!"); } @Override public void onServiceDisconnected(ComponentName name) { mService = null; isConn = false; mTvState.setText("disconnected!"); } }; private int mA; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //开始绑定服务 bindServiceInvoked(); mTvState = (TextView) findViewById(R.id.id_tv_callback); 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) { try { int a = mA++; int b = (int) (Math.random() * 100); //创建一个tv,添加到LinearLayout中 TextView tv = new TextView(MainActivity.this); tv.setText(a + " + " + b + " = caculating ..."); tv.setId(a); mLyContainer.addView(tv); Message msgFromClient = Message.obtain(null, MSG_SUM, a, b); msgFromClient.replyTo = mMessenger; if (isConn) { //往服务端发送消息 mService.send(msgFromClient); } } catch (RemoteException e) { e.printStackTrace(); } } }); } private void bindServiceInvoked() { Intent intent = new Intent(); intent.setAction("com.zhy.aidl.calc"); bindService(intent, mConn, Context.BIND_AUTO_CREATE); Log.e(TAG, "bindService invoked !"); } @Override protected void onDestroy() { super.onDestroy(); unbindService(mConn); } }
在上面的例子中,是传递了基本类型的参数,而我们实际使用中则很多都会需要用到传递自定义类型,这种时候只需要这么做就行了
Message msgFromClient = Message.obtain(null, MSG_SUM, a, b); msgFromClient.replyTo = mMessenger; Bundle bundle = new Bundle(); bundle.putParcelable("data", new User()); msgFromClient.setData(bundle); if (isConn) { //往服务端发送消息 mService.send(msgFromClient); }就是通过在Message中添加Bundle来传递我们自定义的对象,这个对象需要实现Parcelable接口
通过上面的方式可以方便的进行进程间的通讯
那么,为什么通过这种方式可以进行进程间通讯呢?这一点在我解读的文章中也有描述
之前我了解过aidl的进程通讯方式,在aidl的通讯方式可以发现与这里非常相似
1、bindService的方式
2、ServiceConnection的使用
3、aidl接口的对象获取,其实可以发现这里也是一样的
这里调用的通讯方式为Messenger mService = new Messenger(service);
而aidl的接口对象获取方式为:ICalcAIDL mCalcAidl = ICalcAIDL.Stub.asInterface(service);
表面上看起来好像有点不同,但是,如果我们去看Messenger的构造器
public Messenger(IBinder target) { mTarget = IMessenger.Stub.asInterface(target); }
这里返回的mTarget对象为
private final IMessenger mTarget;
跟aidl客户端的方式一模一样,在调用通讯方法send(Message message)我们再去看
public void send(Message message) throws RemoteException { mTarget.send(message); }很明显,其实内部的逻辑方式就是使用的aidl
那么客户端我们发现了是一样的,再去看服务端呢?
在服务端我们的代码是
private Messenger mMessenger = new Messenger(new Handler(handlerThread.getLooper()) { @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; msgfromClient.replyTo.send(msgToClient); } catch (InterruptedException e) { e.printStackTrace(); } catch (RemoteException e) { e.printStackTrace(); } break; } super.handleMessage(msgfromClient); } });然后是
@Override public IBinder onBind(Intent intent) { return mMessenger.getBinder(); }
而aidl的通讯方式是
private final ICalcAIDL.Stub mBinder = new ICalcAIDL.Stub() { @Override public int add(int x, int y) throws RemoteException { return x + y; } @Override public int min(int x, int y) throws RemoteException { return x - y; } };
然后
public IBinder onBind(Intent t) { Log.e(TAG, "onBind"); return mBinder; }就是将一个实现了我们自定义的aidl对象的Stub接口的对象作为通讯方式返回
那么,现在的Messenger方式又是怎样的呢
我们首先来看Messenger的构造器,来看看这这里面做了什么
public Messenger(Handler target) { mTarget = target.getIMessenger(); }这里从我们传入的handler中取出了IMessenger对象
这个IMessenger,其实是依赖一个aidl生成的类
于:
frameworks/base/core/java/android/os/IMessenger.aidl.
package android.os; import android.os.Message; /** @hide */ oneway interface IMessenger { void send(in Message msg); }
这样,在服务端就只差一个东西了,就是实现了IMessenger.Stub的对象,这个对象我们去哪里找?
然后我们去看
public Messenger(Handler target) { mTarget = target.getIMessenger(); }
这里的target.getMessenger()方法,我们进去看一下,可以看到
final IMessenger getIMessenger() { synchronized (mQueue) { if (mMessenger != null) { return mMessenger; } mMessenger = new MessengerImpl(); return mMessenger; } } private final class MessengerImpl extends IMessenger.Stub { public void send(Message msg) { msg.sendingUid = Binder.getCallingUid(); Handler.this.sendMessage(msg); } }找到了!这个MessengerImpl对象就是实现了IMessenger.Stub的对象
这样一来,需要的要素就都齐了,按照现在的代码来推测的话,不难推测出
@Override public IBinder onBind(Intent intent) { return mMessenger.getBinder(); }这里返回的mMessenger.getBinder()应该是MessengerImpl对象,不过我们还是得去确认一下
public IBinder getBinder() { return mTarget.asBinder(); }
这里调用了asBinder()方法,再进去看
@Override public android.os.IBinder asBinder() { return this; }可以看到,asBinder方法就是返回的mTarget对象自己,就是MessengerImpl对象
这里这个asBinder方法的源码是aidl文件在gen路径下生成的类里面可以看到的,如果读者想看的话,可以在aidl的例子中查看,就可以看到
那么Messenger配合Handler的进程间通信的原理到这里就分析结束了,从这个看来的话,其实我们完全也可以自己写一个类似于Messenger的对象用来进行进程间通信,并且利用Message可以传递数据的特性来进行数据的传递,可以说还是非常方便的
相关文章推荐
- Find Cycle
- bootstrap-js(4)标签页
- webkit的基本应用
- python之mock
- 你好,明天
- linux环境下的一种退出后快速返回的方法
- DB2 INTERSECT、EXCEPT、UNION集合操作测试
- codeforces 571 B. Minimization
- 欢迎使用CSDN-markdown编辑器
- C#基础练习题
- 输入框限制,条件是左边输入框输入的数字要小于右边输入框的值,两边输入框要为整型数字。
- iOS(总结)绘图&渐变&NStimer
- EasyUI----EasyUI-Tree联想加模糊查询
- 【面试】-Android基础知识
- JUnit 4的基本用法
- [leetcode-226]Invert Binary Tree(c++)
- 有关python中的id,is 等
- stopPropagation, preventDefault ,cancelBubble和 return false
- 【计算机网络】简单网络管理协议 SNMP
- hdu1241