从AIDL来认识Binder


在平时的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) {
} else { IInterface iin = obj.queryLocalInterface("com.rxdemo.IMyAidlInterface"); return (IMyAidlInterface)(iin != null && iin instanceof IMyAidlInterface?(IMyAidlInterface)iin:new IMyAidlInterface.Stub.Proxy(obj)); } }

queryLocalInterface这个方法里面传入了一个参数,这个参数是descriptor用来表示唯一的AIDL文件,我们看asInterface这个方法返回的逻辑是什么,表示,如果能找到这个iin对象,表示在同一个进程,如果找不到,就需要通过代理对象去实现远程通信,不在一个进程。

我们在启动一个Service的时候,会去使用binderService这个方法来绑定一个服务,可以是同进程的,也可是远程的。

 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) {

            }
        },);

在service bind成功之后,就可以通过IMyAIDLInterface 这个接口对象去调用远程的方法了。







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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值