为了账号安全,请及时绑定邮箱和手机立即绑定

如何理解Android中的AIDL?

如何理解Android中的AIDL?

大吉大利今晚学习 2018-03-09 19:34:38
查看完整描述

1 回答

已采纳
?
这个名字没人起

TA贡献12条经验 获得超7个赞

我们就看看IMyInterface.Stub吧:

public static abstract class Stub extends android.os.Binder implements aidl.IMyInterface {
..........
}

可以看到,Stub是IMyInterface中的一个静态抽象类,继承了Binder,并且实现了IMyInterface接口。这也就解释了我们定义IMyInterface.Stub的时候为什么需要实现IMyInterface中的方法了,也说明了为什么我们可以把IMyInterface.Stub向上转型成IBinder了。

Activity中的IMyInterface 
在Activity中,通过ServiceConnection连接MyService并成功回调onServiceConnected中我们把传回来的IBinder通过IMyInterface.Stub.asInterface(service)转换成为IMyInterface,那就来看看这里是如何转换的吧:

public static abstract class Stub extends android.os.Binder implements aidl.IMyInterface {

..........

public static aidl.IMyInterface asInterface(android.os.IBinder obj) {
   if ((obj == null)) {
       return null;
   }
   
   android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
   if (((iin != null) && (iin instanceof aidl.IMyInterface))) {
       return ((aidl.IMyInterface) iin);
   }
   return new aidl.IMyInterface.Stub.Proxy(obj);
}
}

首先,我们因该明白的是,传回来的IBinder就是我们在Service的onBind( )方法所return的IBinder,然后我们调用Stub中的静态方法asInterface并把返回来的IBinder当参数传进去。 
在asInterface方法中,首先判断了传进来的IBinder是不是null,如果为null就返回一个null;接着就判断传进来的IBinder是不是就在当前进程里面,如果是的话就直接返回IMyInterface,不是的话就返回IMyInterface.Stub.Proxy(obj)。这里我觉得需要明白的是:直接返回的IMyInterface是实现了定义的接口方法getInfor的。因为在IMyInterface.Stub中所实现的。当然如果是在同一进程中,那么我们调用IMyInterface的方法时就是在本地调用方法,直接调用就可以了。

如果没在同一进程,就会返回IMyInterface.Stub.Proxy(obj):

private static class Proxy implements aidl.IMyInterface {
       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 java.lang.String getInfor(java.lang.String s) throws android.os.RemoteException {
           android.os.Parcel _data = android.os.Parcel.obtain();
           android.os.Parcel _reply = android.os.Parcel.obtain();
           java.lang.String _result;
           try {
               _data.writeInterfaceToken(DESCRIPTOR);
               _data.writeString(s);
              //传送数据到远程的
               mRemote.transact(Stub.TRANSACTION_getInfor, _data, _reply, 0);
               _reply.readException();
             //接受从远端传回的数据
               _result = _reply.readString();
           } finally {
               _reply.recycle();
               _data.recycle();
           }
           return _result;
       }
  }
   static final int TRANSACTION_getInfor = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
}

在Proxy中,我们首先把Service连接成功返回的IBinder它的内部变量mRemote,这里在提一下,这里得IBinder还是是MyService中onBind所返回的。然后,当我们调用IMyInterface的方法的时候,其实就是调用的Proxy的方法了,这也是为什么这个类叫做Porxy的原因了。

当调用IMyInterface.getInfor(String s) ,我们就看Proxy中的getInfor,先获取了两个Parcel对象 _data、_data,从变量名就可以看出,一个是传送数据的,另一个则是接受返回数据的。接着,向_data中写入了DESCRIPTOR(也就是这个类的全名),再写入了方法参数。然后就到了最重要的一步了,

mRemote.transact(Stub.TRANSACTION_getInfor, _data, _reply, 0); 
这里我们调用了IBinder的transact方法,来把数据传给远端的服务器。然后在我们远程的MyService中,里面的Stub中就会回调onTransact()(因为你把数据传个远程的服务,远端的服务收到数据也就回调了)

注意:这里是在远程的服务里调用的。

@Overridepublic
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_getInfor: {
           data.enforceInterface(DESCRIPTOR);
           java.lang.String _arg0;
          //取出参数
           _arg0 = data.readString();
          // 远程服务调用自己本地实现的方法获取返回值
           java.lang.String _result = this.getInfor(_arg0);
           reply.writeNoException();
          //写入返回值
           reply.writeString(_result);
           return true;
       }
   }
   return super.onTransact(code, data, reply, flags);
}

onTransact方法是在Stub的内部实现的。

先看一下它的四个参数: 
code:每个方法都有一个int类型的数字用来区分(后面中的swicth),在我们例子中也就是我们Proxy中的Stub.TRANSACTION_getInfor。 
data:传过来的数据,其中包含我们的参数,以及类的描述。 
reply:传回的数据,我们要写入是否发生了Exception,以及返回值 
flags:该方法是否有返回值 ,0表示有返回值。

调用onTransact就表示有数据传来,首先就会通过swicth判断是哪个方法,然后取出方法参数,调用本地实现的方法获取返回值,写入返回值到reply。最后,返回true,才会把数据发送出去,发挥false就不会把结果返回给Activity了。这里也就是说,只有返回true,我们Proxy中才能接受从远端传回的数据。

      //传送数据到远程的
       mRemote.transact(Stub.TRANSACTION_getInfor, _data, _reply, 0)
       _reply.readException()
      //接受从远端传回的数据
       _result = _reply.readString()

注意:Service也是把数据发送出来,让客户端接受的。

Service发出了数据,客户端接收到了,就会一层一层返回去。所以,当我们简单的调用IMyInterface的getInfor时候,先是Proxy的transact发送出数据,然后服务端的onTransact接受并处理传来的数据,再把处理得到的数据写入返回值并发送给客户端,客户端读取值后就成为调用方法的返回值返回了。


查看完整回答
反对 回复 2018-03-09
  • 1 回答
  • 0 关注
  • 863 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信