• Android 进阶——轻量级跨进程传递Message利器Messenger详解


    引言

    作为Android 开发者相信我们对于消息机制一定非常熟悉,对于进程内使用Handler处理Message 也一定了如执掌,而如果让你使用最简洁的方式实现进程间通信,也许有相当一部分初学者想到的是用AIDL自己实现,诚然思路是对的,但是还有更简单的机制供你使用。

    一、Messenger 概述

    Messenger是基于消息Message的传递的一种轻量级IPC进程间通信方式(通过在一个进程中创建一个指向Handler的Messenger,并将该Messenger传递给另一个进程),当然本质就是对Binder的封装(也是通过AIDL实现的 )。通过Messenger可以让我们可以简单地在进程间直接使用Handler进行Message传递,跨进程是通过Binder(AIDL实现),而消息发送是通过Handler#sendMessage方法,而处理则是Handler#handleMessage处理的;当然除了Handler之外还可以是自定义的相关的某些IBinder接口,简而言之,Messenger的跨进程能力是由构造时关联的对象提供的。

    二、Messenger 源码解析

    Messenger 实现了Parcelable接口,意味着自身可以跨进程传递,同时持有IMessenger 接口引用(一个Binder对象)意味着拿到这个Binder对象就可以跨进程使用。Messenger 只是把IMessenger接口包装起来并通过Binder进行跨进程传递,真正的核心能力提供者是IMessenger的实现类——android.os.Handler.MessengerImpl。

    package android.os;
    
    /**
     * Reference to a Handler, which others can use to send messages to it.
     * This allows for the implementation of message-based communication across
     * processes, by creating a Messenger pointing to a Handler in one process,
     * and handing that Messenger to another process.
     */
    public final class Messenger implements Parcelable {
        private final IMessenger mTarget;
    
        /**
         * Create a new Messenger pointing to the given Handler.  Any Message
         * objects sent through this Messenger will appear in the Handler as if
         * {@link Handler#sendMessage(Message) Handler.sendMessage(Message)} had been called directly.
         * 
         * @param target The Handler that will receive sent messages.
         */
        public Messenger(Handler target) {
            mTarget = target.getIMessenger();
        }
    
        /**
         * Create a Messenger from a raw IBinder, which had previously been retrieved with {@link #getBinder}.
         * @param target The IBinder this Messenger should communicate with.
         */
        public Messenger(IBinder target) {
            mTarget = IMessenger.Stub.asInterface(target);
        }
        
        /**
         * Send a Message to this Messenger's Handler.
         * 
         * @param message The Message to send.  Usually retrieved through
         * {@link Message#obtain() Message.obtain()}.
         */
        public void send(Message message) throws RemoteException {
            mTarget.send(message);
        }
        
        /**
         * Retrieve the IBinder that this Messenger is using to communicate with
         * its associated Handler.
         * @return Returns the IBinder backing this Messenger.
         */
        public IBinder getBinder() {
            return mTarget.asBinder();
        }
        
        public boolean equals(Object otherObj) {
            if (otherObj == null) {
                return false;
            }
            try {
                return mTarget.asBinder().equals(((Messenger)otherObj)
                        .mTarget.asBinder());
            } catch (ClassCastException e) {
            }
            return false;
        }
    
        public int hashCode() {
            return mTarget.asBinder().hashCode();
        }
        
        public int describeContents() {
            return 0;
        }
    
        public void writeToParcel(Parcel out, int flags) {
            out.writeStrongBinder(mTarget.asBinder());
        }
    
        public static final Parcelable.Creator<Messenger> CREATOR
                = new Parcelable.Creator<Messenger>() {
            public Messenger createFromParcel(Parcel in) {
                IBinder target = in.readStrongBinder();
                return target != null ? new Messenger(target) : null;
            }
    
            public Messenger[] newArray(int size) {
                return new Messenger[size];
            }
        };
    
        public static void writeMessengerOrNullToParcel(Messenger messenger,
                Parcel out) {
            out.writeStrongBinder(messenger != null ? messenger.mTarget.asBinder()
                    : null);
        }
    
        public static Messenger readMessengerOrNullFromParcel(Parcel in) {
            IBinder b = in.readStrongBinder();
            return b != null ? new Messenger(b) : null;
        }
    }
    
    1、IMessenger接口

    IMessenger是通过AIDL 自动生成的,一般在原生Android系统中I前缀的都是AIDL接口对应的实现类。对应的Messenger.aidl:

    package android.os;
    
    parcelable Messenger;
    

    而IMessenger.aidl里就定义了一个入参为Message的方法 send(in Message msg)

    package android.os;
    
    import android.os.Message;
    
    /** @hide */
    oneway interface IMessenger {
        void send(in Message msg);
    }
    

    Messenger.aidl对应的AIDL实现类:

    public interface IMessenger extends android.os.IInterface {
        /** Local-side IPC implementation stub class. */
        public static abstract class Stub extends android.os.Binder implements
                android.os.IMessenger {
            private static final java.lang.String DESCRIPTOR = "android.os.IMessenger";
    
            public Stub() {
                this.attachInterface(this, DESCRIPTOR);
            }
    
            public static android.os.IMessenger asInterface(...}
    
            public android.os.IBinder asBinder() {
                return this;
            }
    
            @Override
            public boolean onTransact(int code, android.os.Parcel data,
                    android.os.Parcel reply, int flags)
                    throws android.os.RemoteException {...}
    
            private static class Proxy implements android.os.IMessenger {...}
    
        public void send(android.os.Message msg)
                throws android.os.RemoteException;
    }
    

    IMessenger就是一个Binder 接口只提供了一个方法——send 用于跨进程发送消息Message。

    2、Messenger 主要方法
    2.1、Messenger(Handler target)
     public Messenger(Handler target) {
            mTarget = target.getIMessenger();
        }
    

    通过Handler构造Messenger时,就是调用了传入的Handler#getIMessenger()方法得到单例构造的MessengerImpl实例并初始化mTarget。

    //Handler#getIMessenger()    
    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);
            }
        }
    

    本质就是通过Handler#sendMessage完成通信。

    2.2、Messenger(IBinder target)

    而通过IBinder对象构造Messenger时,就是把传入的IBinder对象“转成”MessengerImpl实例并初始化mTarget成员变量。

    并非简单地直接强转而是先检索,如果已经创建过了就直接返回IBinder对应的代理对象,否则创建对应的代理对象再返回,预知详情请后续关注Binder系列文章

    public Messenger(IBinder target) {
        mTarget = IMessenger.Stub.asInterface(target);    
    }
    
    2.3、send(Message message)

    前面分析了send方法本质就是调用Handler#sendMessage方法,这也解释了为什么我们在服务端和客户端都需要创建Handler,因为需要在Handler去处理接收到的消息。

    public void send(Message message) throws RemoteException {
            mTarget.send(message);//MessengerImpl#send
        }
    

    三、Messenger的使用

    Messenger 基于Binder可以跨进程通信,为了方便我简单的把一个进程称之为服务端进程,另一个称之为客户端进程

    1、首先在服务端定义一个Messenger对象

    Messager.replyTo指向的客户端的Messenger,而Messenger又持有客户端的一个IBinder对象(即MessengerImpl),服务端正是利用这个IBinder对象做的与客户端的通信。

    • 创建一个Handler
    • 使用Handler初始化构建Messenger
    package com.crazymo.messenger.rawmessenger;
    
    import android.app.Service;
    import android.content.Intent;
    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.util.Log;
    
    public class MessengerService extends Service {
        public final static String TAG = "MessengerIPC";
        public final static String KEY_NAME = "Name";
        public final static String KEY_RESP = "Response";
        public final static int MSG_WHAT_HELLO = 100;
        public final static int MSG_WHAT_RESP = 1001;
        /**
         * 一个用于跨进程的序列化对象,包裹着IMessenger AIDL接口
         */
        private static final Messenger messenger = new Messenger(new MessengerServerHandler());
    
        private static class MessengerServerHandler extends Handler {
            @Override
            public void handleMessage(Message msg) {
                doHandleMessage(msg);
            }
        }
    
        /**
         * 处理其他进程发过来的消息
         * @param msg
         */
        private static void doHandleMessage(Message msg) {
            if (msg != null) {
                String ret = "hello ";
                //接收客户端的消息并处理
                if (msg.what == MSG_WHAT_HELLO) {
                    Log.e(TAG, "receive msg from client=" + msg.getData().getString(KEY_NAME));
                    try {
                        Thread.sleep(1_000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    ret += msg.getData().getString(KEY_NAME);
                    //把处理结果封装到Message返回给客户端
                    Message reply = Message.obtain(null, MSG_WHAT_RESP);
                    Bundle bundle = new Bundle();
                    bundle.putString(KEY_RESP, ret);
                    reply.setData(bundle);
                    try {
                        //msg.replyTo @ android.os.Messenger类型,Messager.replyTo指向的客户端的Messenger,而Messenger又持有客户端的一个Binder对象(MessengerImpl)。服务端正是利用这个Binder对象做的与客户端的通信。
                        if (msg.replyTo != null) {
                            msg.replyTo.send(reply);
                        }
                    } catch (RemoteException e) {
                        e.printStackTrace();
                    }
                }
            } else {
                Log.e(TAG, "handle client empty msg");
            }
        }
    
        @Override
        public IBinder onBind(Intent intent) {
            //返回Messenger的IBinder对象,当bindService 执行时候就会触发该回调,就可以拿到服务端的IBinder对象
            return messenger.getBinder();
        }
    }
    

    然后就在传入Handler#handleMessage 方法中实现处理消息的逻辑,至此一个远程Service实现完毕。

    2、客户端使用Messenger
    • 定义一个Handler 用于发送Message
    • 初始化Messenger对象
    package com.crazymo.messenger;
    
    import android.annotation.SuppressLint;
    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 com.crazymo.messenger.aidl.MyMessengerService;
    import com.crazymo.messenger.rawmessenger.MessengerService;
    
    public class MainActivity extends AppCompatActivity {
        private final static String TAG="MainActivity";
        /***********************1、Messenger 方式****************************/
        private Messenger mServer;
        private ServiceConnection connMessenger =new ServiceConnection() {
            @Override
            public void onServiceConnected(ComponentName name, IBinder service) {
                mServer=new Messenger(service);//把返回的IBinder对象初始化Messenger
                Log.e(MessengerService.TAG, "MessengerService Connected!");
            }
    
            @Override
            public void onServiceDisconnected(ComponentName name) {
    
            }
        };
    
        private final Handler handlerClient =new Handler(){
            @SuppressLint("HandlerLeak")
            @Override
            public void handleMessage(Message msg) {
                if(msg!=null && msg.what== MessengerService.MSG_WHAT_RESP){
                    String resp=msg.getData().getString(MessengerService.KEY_RESP);
                    Log.e(MessengerService.TAG, "resp from server="+resp);
                }
            }
        };
    
        //为了接收服务端的回复,客户端也需要准备一个接收消息的Messenger 和Handler
        private final Messenger clientMessenger=new Messenger(handlerClient);
    
        private void bindMessengerService() {
            Intent intent=new Intent(this,MessengerService.class);
            bindService(intent, connMessenger, Context.BIND_AUTO_CREATE);
    
        }
    
        public void sendByMessenger(View view) {
            Message msg=Message.obtain(null,MessengerService.MSG_WHAT_HELLO);
            Bundle data=new Bundle();
            data.putString(MessengerService.KEY_NAME,"CrazyMo_");
            msg.setData(data);
            //Client 发信时指定希望回信人,把客户端进程的Messenger对象设置到Message中
            msg.replyTo=clientMessenger;
            try {
                mServer.send(msg);//跨进程传递
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }
    
        /***********************2、MyMessenger AIDL方式****************************/
        private IMyMessenger myInterface;
        private ServiceConnection connAidl = new ServiceConnection() {
            @Override
            public void onServiceConnected(ComponentName name, IBinder service) {
                myInterface = IMyMessenger.Stub.asInterface(service);
                Log.i(TAG, "MyMessenger 连接Service 成功");
            }
            @Override
            public void onServiceDisconnected(ComponentName name) {
                Log.e(TAG, "连接Service失败");
            }
        };
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            bindMessengerService();
            bindMyMessengerService();
        }
    
        @Override
        protected void onDestroy() {
            super.onDestroy();
            unbindService(connMessenger);
            unbindService(connAidl);
        }
    
        public void sendByMyMessenger(View view) {
            try {
                String ret=myInterface.send("hello server my MyMessenger");
                Log.i(TAG, "myInterface.send的结果="+ret);
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }
    
        private void bindMyMessengerService() {
            Intent intent=new Intent(this, MyMessengerService.class);
            bindService(intent, connAidl, Context.BIND_AUTO_CREATE);
        }
    }
    
    3、传统AIDL实现 VS Messenger
    // IMyMessenger.aidl
    package com.crazymo.messenger;
    
    interface IMyMessenger {
    
        String send( String aString);
    }
    
    public class MyMessengerService  extends Service {
    
        private static final String TAG="MyMessengerService";
        private MyMessengerBinder mBinder=new MyMessengerBinder();
        @Override
        public IBinder onBind(Intent intent) {
            return mBinder;
        }
    
        private static class MyMessengerBinder extends IMyMessenger.Stub{
            @Override
            public String send(String aString) throws RemoteException {
                String ret="reply to client"+aString;
                Log.e(TAG,"received str from c:"+aString);
                return ret;
            }
        }
    }
    

    两者对比你会发现以原程服务的形式使用传统AIDL和Messenger大同小异,区别仅仅是在于初始化的时候,当onServiceConnected方法回调时初始化构造远程Binder对象的方式有所差别,剩下的基本一模一样。

    本文转自Android 进阶——轻量级跨进程传递Message利器Messenger详解

  • 相关阅读:
    整数的二进制表示中1的个数
    最长公共子序列
    关于使浏览器崩溃的代码尝试
    wp7 独立存储
    动态引用样式表
    锋利的jQuery小记……
    DataGridVidw添加CheckBox。并通过一个 CheckBox来控制其全选。
    全选按钮的使用。winfrom程序中,对全选按钮的理解,欢迎拍砖!
    Ul li 超出文本显示省略号JS右键控制 本人QQ:267307031 空间更多技术咨询
    FileUpload控件
  • 原文地址:https://www.cnblogs.com/sishuiliuyun/p/16330402.html
Copyright © 2020-2023  润新知