Android Aidl (二)深入了解Aidl

Android Aidl (一)通过实例初探Aidl一文中,我们通过简单的实例,来了解了Aidl在进程与服务之间的通信。

接下来,我们来回答一下,上篇文章我们提出的问题。

具体实现:

1.回顾调用流程

1.1 App1 通过intent与远处的Service关联上,并调用bindService方法绑定。

intent.setPackage("com.example.myapplication2");
intent.setAction("com.example.myapplication2.DownloadService");
this.bindService(intent,conn, Context.BIND_AUTO_CREATE);

1.2 连接服务后,会调用onServiceConnected方法,重要的是做了两件事

  • 通过DownloadAidlInterface.Stub.asInterface(iBinder)获取服务端的DownloadAidlInterface类。
  • 调用在App2实现的方法getProgress来获取模拟的下载进度。
private ServiceConnection conn = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
            final DownloadAidlInterface aidlInterface = DownloadAidlInterface.Stub.asInterface(iBinder);
            ...
            int pro = aidlInterface.getProgress();
            ...
        }
        @Override
        public void onServiceDisconnected(ComponentName componentName) {
        }
};

 有关服务的可以参考文章。

到这里,我们就能感受到,App1进程就像在操作自己定义的类对象一样,通过类方法获取类的成员变量。但是实际是调用远处的Service的类

2.客户端

究竟客户端为什么可以获取DownloadAidlInterface的实例,我们来看看由aidl文件生成的java文件,路径在

我们来分析这个java文件

首先调用的是DownloadAidlInterface.Stub.asInterface(iBinder)

public static abstract class Stub extends android.os.Binder implements com.example.myapplication2.DownloadAidlInterface
{
    public static com.example.myapplication2.DownloadAidlInterface asInterface(android.os.IBinder obj)
    {
        if ((obj==null)) {
        return null;
        }
        android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
        if (((iin!=null)&&(iin instanceof com.example.myapplication2.DownloadAidlInterface))) {
            return ((com.example.myapplication2.DownloadAidlInterface)iin);
        }
        return new com.example.myapplication2.DownloadAidlInterface.Stub.Proxy(obj);
    }
}

 如果iin为空,会创建一个新的Proxy代理对象,我们再继续往下看。

        private static class Proxy implements com.example.myapplication2.DownloadAidlInterface
        {
            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;}
            @Override public int getProgress() throws android.os.RemoteException
            {
                android.os.Parcel _data = android.os.Parcel.obtain();
                android.os.Parcel _reply = android.os.Parcel.obtain();
                int _result;
                try {
                    _data.writeInterfaceToken(DESCRIPTOR);
                    mRemote.transact(Stub.TRANSACTION_getProgress, _data, _reply, 0);
                    _reply.readException();
                    _result = _reply.readInt();
                }
                finally {
                    _reply.recycle();
                    _data.recycle();
                }
                return _result;
            }
        }

 到这一步我们应该可以确定,我们通信的是Proxy这个代理类,也看到了getProgress()方法。(因为我也在调试的时候进入了这里嘿嘿)

我们分析一下getProgress(),不然有点不知所云。

 至于继续往下探索,就是有关binder等的Android的进程的通信机制了,通信机制后面我自己也会继续写,我们先把结论总结出来。

 

 3.服务端

 我们在同样的DownloadAidlInterface.java文件中,能找到onTransact()方法。

  • _data和_reply属于Parcel类,其实是容器,是用来存放数据和读取数据的。在这里,是用来存放和读取在客户端与服务器之间通信的数据。Parcel.obtain()是从容器池里获取容器。_reply.readInt()为读取整型数据,对应服务端的getProgress的返回值类型,同为Int型。recycle()为回收Parcel内存。
  • transact() 方法为客户端与服务器通信的核心方法。执行此方法后,客户端会挂起,等待服务端的数据流回复,返回到_reply的类变量。 
    @Override 
    public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException
    {
        switch (code)
        {
            case INTERFACE_TRANSACTION:
            {
                reply.writeString(DESCRIPTOR);
                return true;
            }
            case TRANSACTION_getProgress:
            {
                data.enforceInterface(DESCRIPTOR);
                int _result = this.getProgress();
                reply.writeNoException();
                reply.writeInt(_result);
                return true;
            }
        }
        return super.onTransact(code, data, reply, flags);
    }

实际此方法对应的是在客户端Transact()方法。原理也还是前面说的Android的通信机制,这里我们先给出结论。

  • 从客户端发来的code,进入了TRANSACTION_getProgress的switch case里面。明显的,在这里调用了this.getProgress()方法,这个this就是继承了我们接口“com.example.myapplication2.DownloadAidlInterface”,调用的结果保存给_result变量。然后调用这里的reply.writeInt(_result)方法,从这里把数据写了进去。能看出来,对应的是客户端里调用了reply.readInt()方法。

 

4.总结

到这里,客户端和服务端的通信已经介绍完毕了。我们用一张图来总结整个调用流程,调用流程为1-2-3。

为了加深对Aidl的认识,我们再来看一下,为什么要用Aidl的方式。

在软件的设计领域类,任何的解决或者优化方案,都是围绕这需求性能来作文章,所以从这个基础上看:

  • 实现基础功能IPC。
  • 在功能实现的基础上,对开发者友好,即方便开发。

所以在此基础上,建立一套模板,把涉及到数据流通信的复杂流程封装起来。对外保留易于理解的接口供开发者使用,这就为对开发者友好。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值