当前位置:   article > 正文

Android Messenger原理

msg.data = bundle

前言

Messenger中文意思是送信者,通过Messenger我们可以在不同进程之间传递Message对象,其底层也是通过上文讲到的AIDL实现的,先来看看基本用法

一、基本用法

以客户端发送消息给服务端,服务端回复一个消息给客户端为例。

  1. // 运行在其它进程
  2. class MessengerService : Service() {
  3. class MessengerHandler : Handler() {
  4. val TAG = "MessengerHandler"
  5. override fun handleMessage(msg: Message?) {
  6. when (msg?.what) {
  7. ADD_BOOK -> {
  8. // 必须设置classLoader不然会抛出异常
  9. msg.data.classLoader = Thread.currentThread().contextClassLoader
  10. Log.d(TAG, "do add book ${msg.data.get("book")}")
  11. val replyMessage = Message.obtain(null, REPLY_ADD_BOOK)
  12. val bundle = Bundle()
  13. bundle.putString("reply", "我收到了响应")
  14. replyMessage.data = bundle
  15. msg.replyTo.send(replyMessage)
  16. }
  17. ALL_BOOKS -> {
  18. Log.d(TAG, "do all books")
  19. }
  20. }
  21. }
  22. }
  23. override fun onBind(intent: Intent?): IBinder? {
  24. val messenger = Messenger(MessengerHandler())
  25. return messenger.binder
  26. }
  27. }
  28. 复制代码

接着在MainActivity中绑定服务,代码如下

  1. class MainActivity : AppCompatActivity() {
  2. private lateinit var connection: ServiceConnection
  3. private lateinit var replyMessenger: Messenger
  4. private var messenger: Messenger? = null
  5. class GetReplyHandler : Handler() {
  6. private var TAG = "MainActivity"
  7. override fun handleMessage(msg: Message?) {
  8. when (msg?.what) {
  9. REPLY_ADD_BOOK -> {
  10. Log.d(TAG, msg.data.getString("reply"))
  11. }
  12. }
  13. }
  14. }
  15. override fun onCreate(savedInstanceState: Bundle?) {
  16. super.onCreate(savedInstanceState)
  17. setContentView(R.layout.activity_main)
  18. connection = object : ServiceConnection {
  19. override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
  20. messenger = Messenger(service)
  21. }
  22. override fun onServiceDisconnected(name: ComponentName?) {
  23. }
  24. }
  25. replyMessenger = Messenger(GetReplyHandler())
  26. val intent = Intent(this, MessengerService::class.java)
  27. bindService(intent, connection, Context.BIND_AUTO_CREATE)
  28. }
  29. fun send(v: View) {
  30. val msg = Message.obtain(null, ADD_BOOK)
  31. // msg.obj = Book(0, "第0本书") 不能使用obj跨进程传递自定义的Parcelable对象,使用Bundle因为其可以设置classLoader
  32. val msg = Message.obtain(null, ADD_BOOK)
  33. val bundle = Bundle()
  34. bundle.putParcelable("book", Book(0, "第0本书"))
  35. msg.data = bundle
  36. msg.replyTo = replyMessenger
  37. messenger?.send(msg)
  38. }
  39. override fun destroy() {
  40. unbindService(connection)
  41. }
  42. }
  43. 复制代码

注意send方法内部发送的Parcelable类(这里是Book)在服务端必须也要存在,这样当调用MainActivity的send方法时就会服务进程就会打印出do add book,下面就来看看该过程的源码

二、源码分析

  • 客户端发送消息给服务端

首先我们在MessengerService的onBind中创建了一个Messenger实例,所以我们就从Messenger构造器开始说起

  1. public Messenger(Handler target) {
  2. mTarget = target.getIMessenger();
  3. }
  4. 复制代码

继续看看Handler的getIMessager

  1. final IMessenger getIMessenger() {
  2. synchronized (mQueue) {
  3. if (mMessenger != null) {
  4. return mMessenger;
  5. }
  6. mMessenger = new MessengerImpl();
  7. return mMessenger;
  8. }
  9. }
  10. 复制代码

刚开始mMessenger肯定为null,继续看看MessengerImpl

  1. private final class MessengerImpl extends IMessenger.Stub {
  2. public void send(Message msg) {
  3. msg.sendingUid = Binder.getCallingUid();
  4. Handler.this.sendMessage(msg);
  5. }
  6. }
  7. 复制代码

这里居然有个Stub!瞬间想起了AIDL,于是就去找了找有没有IMessenger.aidl这个文件,最终找到了该文件,文件内容如下

  1. oneway interface IMessenger {
  2. void send(in Message msg);
  3. }
  4. 复制代码

这里的oneway表示调用send方法并不会挂起当前线程等待服务端执行,而是会立即返回,send方法实现为将收到的消息发送给创建Messenger时的入参,至此服务端的Messenger使用分析完毕接着看看客户端中Messenger的使用,在onServiceConnected中通过传入的Binder对象构造了Messenger对象。

  1. public Messenger(IBinder target) {
  2. mTarget = IMessenger.Stub.asInterface(target);
  3. }
  4. 复制代码

调用asInterface(上篇文章有讲到)拿到IMessenger.Stub.Proxy实例赋值给mTarget,最后客户端通过调用Messengr.send发送消息

  1. public void send(Message message) throws RemoteException {
  2. mTarget.send(message);
  3. }
  4. 复制代码

不管这里send是个直接调用还是IPC调用都会调用到以下MessengerImpl的send方法,该方法又把消息发送到了对应的Handler,因此服务端的Handler就能收到消息了

  • 服务端收到消息回复客户端

注意客户端将replyMessenger设置给了Message.replyTo然后发送消息,这个过程中会调用Message.writeToParcel

  1. public void writeToParcel(Parcel dest, int flags) {
  2. if (callback != null) {
  3. throw new RuntimeException(
  4. "Can't marshal callbacks across processes.");
  5. }
  6. dest.writeInt(what);
  7. dest.writeInt(arg1);
  8. dest.writeInt(arg2);
  9. if (obj != null) {
  10. try {
  11. Parcelable p = (Parcelable)obj;
  12. dest.writeInt(1);
  13. dest.writeParcelable(p, flags);
  14. } catch (ClassCastException e) {
  15. throw new RuntimeException(
  16. "Can't marshal non-Parcelable objects across processes.");
  17. }
  18. } else {
  19. dest.writeInt(0);
  20. }
  21. dest.writeLong(when);
  22. dest.writeBundle(data);
  23. Messenger.writeMessengerOrNullToParcel(replyTo, dest);
  24. dest.writeInt(sendingUid);
  25. }
  26. 复制代码

又会调用到Messenger.writeMessengerOrNullToParcel

  1. public static void writeMessengerOrNullToParcel(Messenger messenger,
  2. Parcel out) {
  3. out.writeStrongBinder(messenger != null ? messenger.mTarget.asBinder()
  4. : null);
  5. }
  6. 复制代码

向Parcel中写入了一个MessengerImpl实例(Binder),然后在IPC结束后会调用Message.readFromParcel

  1. private void readFromParcel(Parcel source) {
  2. what = source.readInt();
  3. arg1 = source.readInt();
  4. arg2 = source.readInt();
  5. if (source.readInt() != 0) {
  6. obj = source.readParcelable(getClass().getClassLoader());
  7. }
  8. when = source.readLong();
  9. data = source.readBundle();
  10. replyTo = Messenger.readMessengerOrNullFromParcel(source);
  11. sendingUid = source.readInt();
  12. }
  13. 复制代码

又调用到了Messenger.readMessengerOrNullFromParcel

  1. public static Messenger readMessengerOrNullFromParcel(Parcel in) {
  2. IBinder b = in.readStrongBinder();
  3. return b != null ? new Messenger(b) : null;
  4. }
  5. 复制代码

如果是跨进程传递那么读取的会是一个BinderProxy对象,通过该BinderProxy构造Messenger对象其内部的mTarget就会是一个IMessenger.Stub.Proxy实例,因此服务端就可以调用客户端的对应方法了

转载于:https://juejin.im/post/5cb59f24f265da03914d573a

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/AllinToyou/article/detail/122583
推荐阅读
相关标签
  

闽ICP备14008679号