跨进程通信Messenger是如何实现的

比如有这样一个需求,APP检测到需要更新,为了不影响我们本应用,我们需要别外开启一个服务进程来下载这个APK,这就涉及到了二个进程进行通信.

这样我们就可以使用Messenger,Messenger他其实就是对AIDL的再次封装.

Messenger里面有二个构造方法,分别是传Handler,IBinder. 还有一个成员变量IMessenger target, 不管哪种构造方法都是为了给target赋值,

当以Handler(handler)作为构造参数的时候,会调用handler.getIMessenger方法获取到一个IMessenger并赋值给target.而Handler的getIMessenger方法里就会实例化出一个MessengerImpl也就是IMessenger这个接口的实现类.

    public Messenger(Handler target) {
        mTarget = target.getIMessenger();
    }
//Handler里的方法
    final IMessenger getIMessenger() {
        synchronized (mQueue) {
            if (mMessenger != null) {
                return mMessenger;
            }
            mMessenger = new MessengerImpl();
            return mMessenger;
        }
    }
//Handler中的私有的静态内部类
    private final class MessengerImpl extends IMessenger.Stub {
        public void send(Message msg) {
            msg.sendingUid = Binder.getCallingUid();
            Handler.this.sendMessage(msg);
        }
    }

当以IBinder(binder)作为参数的时候,他会通过IMessenger.Stub.asInstace(binder)实例化出IMessenger.Stub.Proxy代理类

    public Messenger(IBinder target) {
        mTarget = IMessenger.Stub.asInterface(target);
    }

先来说服务端(DownLoadService) 在DownLoadService中的生命周期onBInd方法中需要返回一个IBinder.这个时候我们就需要创建出一个以Handler为构造参数的Messenger,并通过Messenger.getBinder()返回.

public class MessengerSevice  extends Service {
    Messenger mMessenger = new Messenger(new Handler(new Handler.Callback() {
        @Override
        public boolean handleMessage(Message msg) {

            String sfsdf = msg.getData().getString("sfsdf");

            Messenger replyTo = msg.replyTo;

            return false;
        }
    }));

    @Override
    public IBinder onBind(Intent intent) {
        return mMessenger.getBinder();
    }
}

Messenger.getBinder()返回的其实就是MessengerImpl,为什么呢,

   
    public IBinder getBinder() {
        //1.mTarget
        return mTarget.asBinder();
    }

在注释1中,这个mTarget其实就是在构造方法中的MessengerImpl,而mTarget.asBinder在aidl生成的接口文件中得到的就是自己.

 

所以在客户端bindService绑定成功的时候,获取到的IBinder就是服务端的MessengerImpl

在绑定成功回调方法中,通过以服务端的IBinder为参数构造出可以跟服务端发送消息的Messenger


    ServiceConnection conn = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            //1:service
            mServiceMessenger = new Messenger(service);
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            mServiceMessenger = null;
        }
    };

在注释1中的service其实就是服务端的MessengerImpl.

当客户端要向服务端发送消息的时候,mServiceMessenger.send(msg);

 

    public void sendMessage(View view) {
        if (mServiceMessenger != null) {
            try {
                Message obtain = Message.obtain();
                //这里先不做讨论,下面会讲
                obtain.replyTo = mClientMessenger;
                //1:send方法
                mServiceMessenger.send(obtain);
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }
    }

在注释1中的send方法是怎么操作的: Messenger.send方法其实是通过IMessenger.send方法来操作的,而这个时候的IMessenger就是服务端的IBinder的实现类MessengerIml,就是通过这个类的send方法来发送消息的

再来看这个类

    private final class MessengerImpl extends IMessenger.Stub {
        public void send(Message msg) {
            msg.sendingUid = Binder.getCallingUid();
            Handler.this.sendMessage(msg);
        }
    }

很明显了,就是通过自身的Handler来sendMessage的,这样就会来到服务端的handlerMessage方法中,就可以获取到里面的参数.

这就客户端向服务端发送数据服务端就可以接收.这个时候下载的操作就可以在服务端操作了.

下载进度是如何传递给客户端的呢

这个就相对简单,在Message这个类中有一个成员变量 replyTo.我们在客户端的时候就需要以Handler为参数构造出一个Messenger.并赋值给replyTo

    public void sendMessage(View view) {
        if (mServiceMessenger != null) {
            try {
                Message obtain = Message.obtain();
                //这里就将客户端的Messenger传递给了服务端
                obtain.replyTo = mClientMessenger;
                mServiceMessenger.send(obtain);
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }
    }

 

所以服务端拿到了客户端的Messenger就可以使用客户端的Messenger来向客户端传递消息.

        public boolean handleMessage(Message msg) {

            String sfsdf = msg.getData().getString("sfsdf");

            Messenger replyTo = msg.replyTo;
            Message message = Message.obtain();
            Bundle bundle = new Bundle();
            bundle.putString("client","我是服务端,向客户端发送消息");
            message.setData(bundle);
            try {
                replyTo.send(message);
            } catch (RemoteException e) {
                e.printStackTrace();
            }
            return false;
        }

这样双方就可以互相交流

 

最后赋上AIDL文件生成的java类

/*
 * This file is auto-generated.  DO NOT MODIFY.
 * Original file: /Volumes/windows/android_studio/binder/app/src/main/aidl/con/ancely/binder/IMessenger.aidl
 */
package con.ancely.binder;
// Declare any non-default types here with import statements

public interface IMessenger extends android.os.IInterface {
    /**
     * Local-side IPC implementation stub class.
     */
    public static abstract class Stub extends android.os.Binder implements con.ancely.binder.IMessenger {
        private static final java.lang.String DESCRIPTOR = "con.ancely.binder.IMessenger";

        /**
         * Construct the stub at attach it to the interface.
         */
        public Stub() {
            this.attachInterface(this, DESCRIPTOR);
        }

        /**
         * Cast an IBinder object into an con.ancely.binder.IMessenger interface,
         * generating a proxy if needed.
         */
        public static con.ancely.binder.IMessenger asInterface(android.os.IBinder obj) {
            if ((obj == null)) {
                return null;
            }
            android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
            if (((iin != null) && (iin instanceof con.ancely.binder.IMessenger))) {
                return ((con.ancely.binder.IMessenger) iin);
            }
            return new con.ancely.binder.IMessenger.Stub.Proxy(obj);
        }

        @Override
        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 {
            java.lang.String descriptor = DESCRIPTOR;
            switch (code) {
                case INTERFACE_TRANSACTION: {
                    reply.writeString(descriptor);
                    return true;
                }
                case TRANSACTION_send: {
                    data.enforceInterface(descriptor);
                    con.ancely.binder.Message _arg0;
                    if ((0 != data.readInt())) {
                        _arg0 = con.ancely.binder.Message.CREATOR.createFromParcel(data);
                    } else {
                        _arg0 = null;
                    }
                    this.send(_arg0);
                    reply.writeNoException();
                    return true;
                }
                default: {
                    return super.onTransact(code, data, reply, flags);
                }
            }
        }

        private static class Proxy implements con.ancely.binder.IMessenger {
            private android.os.IBinder mRemote;

            Proxy(android.os.IBinder remote) {
                mRemote = remote;
            }

            @Override
            public android.os.IBinder asBinder() {
                return mRemote;
            }

            public java.lang.String getInterfaceDescriptor() {
                return DESCRIPTOR;
            }

            /**
             * Demonstrates some basic types that you can use as parameters
             * and return values in AIDL.
             */
            @Override
            public void send(con.ancely.binder.Message message) throws android.os.RemoteException {
                android.os.Parcel _data = android.os.Parcel.obtain();
                android.os.Parcel _reply = android.os.Parcel.obtain();
                try {
                    _data.writeInterfaceToken(DESCRIPTOR);
                    if ((message != null)) {
                        _data.writeInt(1);
                        message.writeToParcel(_data, 0);
                    } else {
                        _data.writeInt(0);
                    }
                    mRemote.transact(Stub.TRANSACTION_send, _data, _reply, 0);
                    _reply.readException();
                } finally {
                    _reply.recycle();
                    _data.recycle();
                }
            }
        }

        static final int TRANSACTION_send = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
    }

    /**
     * Demonstrates some basic types that you can use as parameters
     * and return values in AIDL.
     */
    public void send(con.ancely.binder.Message message) throws android.os.RemoteException;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值