26
2017
09

Android AIDL接口方法详解

有关AIDL的使用我就不多说了,今天主要讲的是AIDL的方法作用
AIDL是定义接口的一种语言,多使用跨进程通信的场景,比方说你现在需要获取到服务端的数据(这个服务端不是指提供接口的后台,而是与你当前应用不在一个进程的程序),这个时候你就需要跨进程去获取数据了.
OK,我们先看一下系统生成的AIDL接口:

public interface GetTokenService extends android.os.IInterface {
/**
* Local-side IPC implementation stub class.
* 内部类的实现
* 实际上这个stub类就是一个binder类,我会对每个方法都一个解释,然后再做一下总结
*/
public static abstract class Stub extends android.os.Binder implements com.sumaott.auth.service.GetTokenService {

    private static final java.lang.String DESCRIPTOR = "当前类的路径,会自动生成";   //标识方法

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

    /**
     * Cast an IBinder object into an com.sumaott.auth.service.GetTokenService interface,
     * generating a proxy if needed.
     * 将服务端的binder对象转换成客户端所需要的AIDL对象,如果在同进程中,返回stub本身,否则返回stub.proxy
     * 我们可以看代码
     */
    public static com.sumaott.auth.service.GetTokenService asInterface(android.os.IBinder obj) {
        if ((obj == null)) {
            return null;
        }
        android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
       if (((iin != null) && (iin instanceof com.sumaott.auth.service.GetTokenService))) {   //这里是区分是否在一个进程中
            **return ((com.sumaott.auth.service.GetTokenService) iin);**  //  返回stub本身
        }
        **return new com.sumaott.auth.service.GetTokenService.Stub.Proxy(obj);**  否则返回stub.proxy
    }

    @Override
    public android.os.IBinder asBinder() {   //返回当前的Binder对象
        return this;    
    }


    @Override
    public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException {
     //通过code确定客户端请求的目标方法是什么,
        switch (code) {  
            case INTERFACE_TRANSACTION: {    //接口错误,没找到对应的目标方法
                reply.writeString(DESCRIPTOR);
                return true;
            }
            case TRANSACTION_getToken: {   //如果找到了对应的目标方法,执行方法,再向reply中写入返回值_result
                data.enforceInterface(DESCRIPTOR);
                java.lang.String _result = this.getToken();
                reply.writeNoException();
                reply.writeString(_result);
                return true;
            }
        }
        return super.onTransact(code, data, reply, flags);
    }

   //这个方法是运行在客户端的
    private static class Proxy implements com.sumaott.auth.service.GetTokenService {
        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 java.lang.String getToken() throws android.os.RemoteException {
            //创建输入型对象_data,输出型对象_reply,返回值对象_result
            android.os.Parcel _data = android.os.Parcel.obtain();
            android.os.Parcel _reply = android.os.Parcel.obtain();
            java.lang.String _result;
            try {
                _data.writeInterfaceToken(DESCRIPTOR);
                //调用transact方法来发起RPC请求,同时将当期线程挂起,等待服务端的onTransact方法被调用直到RPC过程返     回,当期线程继续执行
                mRemote.transact(Stub.TRANSACTION_getToken, _data, _reply, 0);
                _reply.readException();
                _result = _reply.readString();
            } finally {
                _reply.recycle();
                _data.recycle();
            }
            return _result;  //在将获取到的值返回
        }
    }

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

/**
 * Demonstrates some basic types that you can use as parameters
 * and return values in AIDL.
 */
public java.lang.String getToken() throws android.os.RemoteException;

}

注: GetTokenService 是类名,这个你可以自己去定义,getToken()方法是获取对应数据的一个类,你在获取数据时,需改成与服务端对应的数据结构和方法名

整个运行的逻辑: 首先使用整型ID去标识方法,如果有两个方法则再加一个整型ID,,接着声明了一个内部类stub类,然后通过asInterface方法去判断当前在是否在同一进程中,如果在,返回Stub对象,否则返回Stub.proxy对象, ,,在返回Stub.proxy对象之前会去执行Stub的Proxy内部代理类,然后在Proxy类里去调用transact方法来启动RPC(远程调用服务),同时会将当前线程挂起,然后onTransact方法会被执行,并将获取到的数据写入reply中,然后等到RPC过程结束后,回到当前线程也就是Proxy类里的getToken() 方法,然后获取到RPC之前写入在reply中的数据,最终我们就可以拿到对应的数据了

备注:RPC是耗时服务,不要在UI线程里去做这步操作

上一篇:Android探索之旅(第三十一篇)Android 程序员变量命名神器——CodeLf 下一篇:AWK