Android中Messenger原理及基本用法详解
这边博客主要记录一下android中messenger的基本原理和用法。
简单来讲,messenger其实就是binder通信的包装器,是一种基于消息传递的进程间通信工具。
//messenger实现了parcelable接口,因此可以跨进程传输 public final class messenger implements parcelable { ............... }
通常情况下,我们可以在a进程中创建一个messenger,然后将该messenger传递给b进程。
于是,b进程就可以通过messenger与a进程通信了。
messenger通常与handler一起使用,我们看看对应的源码:
public final class messenger implements parcelable { private final imessenger mtarget; public messenger(handler target) { mtarget = target.getimessenger(); } ........... }
跟进一下handler的getimessenger函数:
............. final imessenger getimessenger() { synchronized (mqueue) { if (mmessenger != null) { return mmessenger; } //返回的是handler中定义的messengerimpl mmessenger = new messengerimpl(); return mmessenger; } } //此处messengerimpl继承自imessenger.stub //容易看出messengerimpl将作为binder通信的接收端 private final class messengerimpl extends imessenger.stub { public void send(message msg) { msg.sendinguid = binder.getcallinguid(); handler.this.sendmessage(msg); } }
从上述代码可以看出,messenger实际上作为了一个binder服务端的wrapper。
当我们在a进程中创建messenger,然后传递给b进程时,messenger需要执行parcelable接口定义的操作,于是:
//在a进程中将binder信息写入到parcel中 public void writetoparcel(parcel out, int flags) { out.writestrongbinder(mtarget.asbinder()); } public static final parcelable.creator<messenger> creator = new parcelable.creator<messenger>() { //在b进程中,重新创建binder public messenger createfromparcel(parcel in) { ibinder target = in.readstrongbinder(); //调用messenger的另一个构造函数 return target != null ? new messenger(target) : null; } public messenger[] newarray(int size) { return new messenger[size]; } };
跟进一下messenger的另一个构造函数:
public messenger(ibinder target) { //得到的是binder通信的客户端 mtarget = imessenger.stub.asinterface(target); }
因此,当messenger从进程a传递到进程b时,它就变为了binder通信客户端的wrapper。
当在进程b中使用messenger的接口时:
public void send(message message) throws remoteexception { //mtarget为binder通信的客户端,将消息发送给服务端的send函数 //即服务端handler的messengerimpl的send函数 //上文已经附上了对应代码,可以看到对应的消息将递交给handler处理 mtarget.send(message); }
以上就是messenger通信的原理,现在实际测试一下。
我们定义一个简单的demo,包含一个activity和一个service,其中service与activity处在不同的进程中。
androidmanifest.xml中的定义如下:
..................... <activity android:name=".mainactivity"> <intent-filter> <action android:name="android.intent.action.main"/> <category android:name="android.intent.category.launcher"/> </intent-filter> </activity> <service android:name=".remoteservice" android:enabled="true" android:exported="true" <!--指定服务运行在其它进程--> android:process=".remote"> </service> ..............
activity的界面很简单,当点击时就会像service发送消息,activity代码如下:
public class mainactivity extends appcompatactivity { private button mbutton; @override protected void oncreate(bundle savedinstancestate) { super.oncreate(savedinstancestate); setcontentview(r.layout.activity_main); //打印activity的pid及所在进程名称 log.d("zjtest", "activity, pid: " + process.mypid() + ", name: " + util.getprocessname(this)); //启动服务 startservice(); //绑定服务 bindservice(); mbutton = (button) findviewbyid(r.id.test_button); mbutton.setenabled(false); //点击按键后,利用messenger向service发送消息 mbutton.setonclicklistener(new view.onclicklistener() { @override public void onclick(view v) { if (mmessenger != null) { try { message msg = message.obtain(); msg.what = 1; mmessenger.send(msg); } catch (remoteexception e) { log.d("zjtest", e.tostring()); } } } }); } @override public void ondestroy() { super.ondestroy(); unbindservice(); stopservice(); } private intent mintent; private void startservice() { mintent = new intent(this, remoteservice.class); this.startservice(mintent); } private serviceconnection mserviceconnection; private void bindservice() { mserviceconnection = new localserviceconnection(); this.bindservice(mintent, mserviceconnection, bind_auto_create); } messenger mmessenger; private class localserviceconnection implements android.content.serviceconnection { @override public void onserviceconnected(componentname name, ibinder service) { //绑定服务后,获得messenger并激活button mmessenger = new messenger(service); mbutton.setenabled(true); } @override public void onservicedisconnected(componentname name) { mbutton.setenabled(false); } } private void stopservice() { stopservice(mintent); } private void unbindservice() { unbindservice(mserviceconnection); } }
service对应的代码如下:
public class remoteservice extends service { private messenger mmessenger; @override public void oncreate() { super.oncreate(); //同样打印进程号及名称 log.d("zjtest", "service, pid: " + process.mypid() + ", name: " + util.getprocessname(this)); localhandler mhandler = new localhandler(); mmessenger = new messenger(mhandler); } private static class localhandler extends handler{ @override public void handlemessage(message msg) { log.d("zjtest", "receive msg: " + msg.what); } } @override public ibinder onbind(intent intent) { //被绑定时,返回messenger return mmessenger.getbinder(); } }
获取进程名的代码如下:
class util { static string getprocessname(context context) { int pid = process.mypid(); activitymanager am = (activitymanager) context .getsystemservice(context.activity_service); for (activitymanager.runningappprocessinfo appprocessinfo: am.getrunningappprocesses()) { if (appprocessinfo.pid == pid) { return appprocessinfo.processname; } } return null; } }
上述代码都是比较简单的,现在来看看运行结果:
02-20 21:25:15.760 d/zjtest (30460): activity, pid: 30460, name: stark.a.is.zhang.messengertest
02-20 21:25:15.769 d/zjtest (30428): service, pid: 30428, name: .remote
02-20 21:25:32.111 d/zjtest (30428): receive msg: 1
从log可以看出,activity与servie运行在不同的进程中,messenger确实可以在不同进程间传递消息。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
推荐阅读
-
Android中Messenger原理及基本用法详解
-
Android中的Selector的用法详解及实例
-
IOS开发中NSURL的基本操作及用法详解
-
Android中onInterceptTouchEvent、dispatchTouchEvent及onTouchEvent的调用顺序及内部原理详解
-
详解关于react-redux中的connect用法介绍及原理解析
-
IOS开发中NSURL的基本操作及用法详解
-
Android中onInterceptTouchEvent、dispatchTouchEvent及onTouchEvent的调用顺序及内部原理详解
-
对jQuery中prev + next选择器的基本介绍及用法详解
-
对jQuery中prev + next选择器的基本介绍及用法详解
-
详解关于react-redux中的connect用法介绍及原理解析