在平时的Android开发过程中,很少接触到Binder,对这个东西也是带了几分畏惧,虽然知道这个很重要,但是,理解起来却不是一件容易的事情。今天就带大家从AIDL来分析Binder。 
Binder是一个C/S架构,就是说分为客户端跟服务端。这里的客户端跟服务端不是我们平时开发中所说的那样,这里的客户端是指发送消息的一端,服务端是指接受消息的一端。 
Binder在进程间通信发挥了很大的作用,起到了一个媒介的作用,谁给谁发送或者接受消息都要通过它。这里的进程间通信不只是单纯的值多个进程之间,一个进程里的通信也是通过Binder,像四大组件的通信,这些都是通过Binder的。 
相信大家也或多或少的使用过AIDL来实现进程间通信,在Androidstudio中,可以通过新建一个AIDL文件,然后,编译器自动帮我们生成这样一个文件,不需要我们手动再去编写,提供了很大的便利。下面我们来看下编译器帮我们生成的AIDL文件长什么样子。

public interface IMyAidlInterface extends IInterface {
    void basicTypes(int var1, long var2, boolean var4, float var5, double var6, String var8) throws RemoteException;

    public abstract static class Stub extends Binder implements IMyAidlInterface {
        private static final String DESCRIPTOR = "com.rxdemo.IMyAidlInterface";
        static final int TRANSACTION_basicTypes = 1;

        public Stub() {
            this.attachInterface(this, "com.rxdemo.IMyAidlInterface");
        }

        public static IMyAidlInterface asInterface(IBinder obj) {
            if(obj == null) {
                return null;
            } else {
                IInterface iin = obj.queryLocalInterface("com.rxdemo.IMyAidlInterface");
                return (IMyAidlInterface)(iin != null && iin instanceof IMyAidlInterface?(IMyAidlInterface)iin:new IMyAidlInterface.Stub.Proxy(obj));
            }
        }

        public IBinder asBinder() {
            return this;
        }

        public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
            switch(code) {
            case 1:
                data.enforceInterface("com.rxdemo.IMyAidlInterface");
                int _arg0 = data.readInt();
                long _arg1 = data.readLong();
                boolean _arg2 = 0 != data.readInt();
                float _arg3 = data.readFloat();
                double _arg4 = data.readDouble();
                String _arg5 = data.readString();
                this.basicTypes(_arg0, _arg1, _arg2, _arg3, _arg4, _arg5);
                reply.writeNoException();
                return true;
            case 1598968902:
                reply.writeString("com.rxdemo.IMyAidlInterface");
                return true;
            default:
                return super.onTransact(code, data, reply, flags);
            }
        }

        private static class Proxy implements IMyAidlInterface {
            private IBinder mRemote;

            Proxy(IBinder remote) {
                this.mRemote = remote;
            }

            public IBinder asBinder() {
                return this.mRemote;
            }

            public String getInterfaceDescriptor() {
                return "com.rxdemo.IMyAidlInterface";
            }

            public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException {
                Parcel _data = Parcel.obtain();
                Parcel _reply = Parcel.obtain();

                try {
                    _data.writeInterfaceToken("com.rxdemo.IMyAidlInterface");
                    _data.writeInt(anInt);
                    _data.writeLong(aLong);
                    _data.writeInt(aBoolean?1:0);
                    _data.writeFloat(aFloat);
                    _data.writeDouble(aDouble);
                    _data.writeString(aString);
                    this.mRemote.transact(1, _data, _reply, 0);
                    _reply.readException();
                } finally {
                    _reply.recycle();
                    _data.recycle();
                }

            }
        }
    }
}


首先是要继承自IInterface,这是肯定的,编写AIDL时都需要继承这个接口。


我们可以看到这里生成了两个内部类,Stub 跟 Proxy  ,Stub 继承自Binder 并且实现了IMyAidlInterface, 可以看出这是一个Binder, Proxy 实现了  IMyAidlInterface这个接口,从名字上面可以看到这是一个代理类。这里其实就是一个服务端跟客户端。现在,假设有两个进程,A和B ,当A向B发消息的时候,会通过代理类Proxy,向Binder 发送消息,然后Binder 再把这个消息发给进程B的Stub对象,完成一次进程间通信,这里也充分的说明了Binder 既可以是服务端也可以是客户端,主要取决于是接受消息还是发送消息。

在Proxy这个代理类里面有这样一段代码


Parcel _data = Parcel.obtain();
                Parcel _reply = Parcel.obtain();

                try {
                    _data.writeInterfaceToken("com.rxdemo.IMyAidlInterface");
                    _data.writeInt(anInt);
                    _data.writeLong(aLong);
                    _data.writeInt(aBoolean?1:0);
                    _data.writeFloat(aFloat);
                    _data.writeDouble(aDouble);
                    _data.writeString(aString);
                    this.mRemote.transact(1, _data, _reply, 0);
                    _reply.readException();
                } finally {
                    _reply.recycle();
                    _data.recycle();
                }



注意到没有,创建了一个reply对象,然后 通过 this.mRemote.transact 方法将数据打包发送出去。这个方法是非常重要的,客户端向服务端发送消息就是通过这个方法,也就是说这个方法是在客户端的。我们再看 Stub这个类里面是怎么接收消息的。

public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
            switch(code) {
            case 1:
                data.enforceInterface("com.rxdemo.IMyAidlInterface");
                int _arg0 = data.readInt();
                long _arg1 = data.readLong();
                boolean _arg2 = 0 != data.readInt();
                float _arg3 = data.readFloat();
                double _arg4 = data.readDouble();
                String _arg5 = data.readString();
                this.basicTypes(_arg0, _arg1, _arg2, _arg3, _arg4, _arg5);
                reply.writeNoException();
                return true;
            case 1598968902:
                reply.writeString("com.rxdemo.IMyAidlInterface");
                return true;
            default:
                return super.onTransact(code, data, reply, flags);
            }
        }


onTransact 这个方法是在服务端的,用于接收消息。

在Stub这个类里面有一个asInterface方法,

public static IMyAidlInterface asIn
                return null;terface(IBinder obj) {
            if(obj == null) {
 this.bindService(intent, new ServiceConnection() {
            @Override
            public void onServiceConnected(ComponentName name, IBinder service) {
                try {
                    IMyAidlInterface asInterface=IMyAidlInterface.Stub.asInterface(service);
                    asInterface.testBinder();
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
            }

            @Override
            public void onServiceDisconnected(ComponentName name) {

            }
        },);