AIDL的原理以及demo

第一部分 AIDL的概念以及使用步骤

Android系统中的进程之间不能共享内存,因此,需要提供一些机制在不同进程之间进行数据通信。

为了使其他的应用程序也可以访问本应用程序提供的服务,Android系统采用了远程过程调用(Remote Procedure Call,RPC)方式来实现。与很多其他的基于RPC的解决方案一样,Android使用一种接口定义语言(Interface Definition Language,IDL)来公开服务的接口。这种可以跨进程访问的服务称为AIDL(Android Interface Definition Language)服务。所以AIDL服务专门是用来解决进程间通信的(IPC)。

AIDL的使用步骤如下:

第一步:定义接口语言,在Android工程的Java包目录中建立一个扩展名为aidl的文件,与java目录同级

// IMyAidlInterface.aidl
package com.example.nft.myapplication;

// Declare any non-default types here with import statements

 interface IMyAidlInterface {
       String getInfor(String s);
       int add(int a,int b);
}

点击Rebuild project按钮就可以在app/generated/source/aidl/debug/aidl里面发现由IMyAidlInterface.aidl文件生成的java文件。

第二步:新建service子类,并利用Binder来实现由aidl定义的方法

public class RemoteService extends Service {
    private IBinder binder = new IMyAidlInterface.Stub() {
        @Override
        public String getInfor(String s) throws RemoteException {
            Log.i("niuniu ", " 收到了客户端的请求 " +s);
            return "我是远程Service返回的数值";
        }

        @Override
        public int add(int a, int b) throws RemoteException {
            Log.i("niuniu ", " 收到了客户端的数据 a = " + a +"  b = " +b);
            return a+b;
        }
    };
    @Override
    public void onCreate() {
        super.onCreate();
        Log.i("niuniu", " RemoteService oncreate");
    }

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return binder;
    }
}

第三步:在AndroidManifest.xml文件中配置RemoteService

        <service android:name=".RemoteService" >
            <intent-filter>
                <action android:name="com.nft.application">
                </action>
            </intent-filter>
        </service>

通过AIDL来建立远程服务的通信机制就到此完成了。接下来,以activity作为客户端的demo,与远程服务进行IPC

首先新建一个project,同样的新建AIDL 文件夹,并把服务端的aidl文件copy到客户端,包括包名,要保持一致,再 rebuild project 

其次是在该应用下的MainActivity中绑定远程,并在onServiceConnected回调方法中调用由远程服务实现aidl定义的方法

public class MainActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        setContentView(R.layout.activity_main);

        MyCon myCon = new MyCon();
        Intent intent = new Intent();
        intent.setPackage("com.example.nft.myapplication");
        intent.setAction("com.nft.application");
        bindService(intent,myCon, Context.BIND_AUTO_CREATE);
    }
    public class MyCon implements ServiceConnection {
        private IMyAidlInterface iService;
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            Log.i("niuniu"," service 连接成功");
            iService = IMyAidlInterface.Stub.asInterface(service);
            try {
                String s = iService.getInfor(" 当前应用传进去的参数");
                Log.i("niuniu", " 从远程服务返回的数值是: "+s);
                int sum = iService.add(3,2);
                Log.i("niuniu", " 从远程服务返回的和: "+sum);
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }
        @Override
        public void onServiceDisconnected(ComponentName name) {

        }
    }
}

试运行的结果

03-01 15:51:25.313 13925 13925 I niuniu  :  service 连接成功
03-01 15:51:25.315 13604 13642 I niuniu  :  收到了客户端的请求  当前应用传进去的参数
03-01 15:51:25.315 13925 13925 I niuniu  :  从远程服务返回的数值是: 我是远程Service返回的数值
03-01 15:51:25.315 13604 13627 I niuniu  :  收到了客户端的数据 a = 3  b = 2
03-01 15:51:25.315 13925 13925 I niuniu  :  从远程服务返回的和: 5

当客户端连接service成功后,就将 "当前应用传进去的参数"传递给远程服务,远程服务收到请求就有log输出,并return相应的结果,客户端通过调用其方法可以得到远程方法的返回值。

结论:这就是远程service利用aidl机制实现与客户端activity之间的数据通信,aidl作为公共服务接口,在远程service中实现,在activity中通过绑定远程服务service来实现参数的传递以及返回值的获取。

第二部分:AIDL的原理

不管是在远程服务中还是在本地客户端中,建立好aidl文件后,都需要rebuild project ,此时会在app/generated/source/aidl/debug/aidl里面看到相应的java文件了

package com.example.nft.myapplication;
// Declare any non-default types here with import statements

public interface IMyAidlInterface extends android.os.IInterface {
    /**
     * Local-side IPC implementation stub class.
     */
    public static abstract class Stub extends android.os.Binder implements com.example.nft.myapplication.IMyAidlInterface {
        private static final java.lang.String DESCRIPTOR = "com.example.nft.myapplication.IMyAidlInterface";

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

        /**
         * Cast an IBinder object into an com.example.nft.myapplication.IMyAidlInterface interface,
         * generating a proxy if needed.
         */
        public static com.example.nft.myapplication.IMyAidlInterface asInterface(android.os.IBinder obj) {
            if ((obj == null)) {
                return null;
            }
           //检查obj是不是当前进程中的binder
            android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
            if (((iin != null) && (iin instanceof com.example.nft.myapplication.IMyAidlInterface))) {
                return ((com.example.nft.myapplication.IMyAidlInterface) iin);
            }
            return new com.example.nft.myapplication.IMyAidlInterface.Stub.Proxy(obj);
        }

        @Override
        public android.os.IBinder asBinder() {
            return this;
        }
/**参数说明:code,区分不同类型的接口,比如,在例子中Stub.TRANSACTION_getInfor
data:从客户端传过来的数据,包含方法参数以及类的描述,
reply:远程服务处理后的数据,返回给客户端,包括是否发生了异常以及返回的结果
flags:该方法是否有返回值,0表示有*/
        @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_getInfor: {
//当客户端将数据传递成功后,会回调该方法,并将类名,以及传递进来的方法参数一并取出来,供RemonteService中binder重写的getinfor使用
                    data.enforceInterface(DESCRIPTOR);
                    java.lang.String _arg0;
                    _arg0 = data.readString();
                    java.lang.String _result = this.getInfor(_arg0);
                   //将远程服务中的结果,写入repy中,发送给客户端proxy
                    reply.writeNoException();
                    reply.writeString(_result);
                    return true;
                }
                case TRANSACTION_add: {
                    data.enforceInterface(DESCRIPTOR);
                    int _arg0;
                    _arg0 = data.readInt();
                    int _arg1;
                    _arg1 = data.readInt();
                    int _result = this.add(_arg0, _arg1);
                    reply.writeNoException();
                    reply.writeInt(_result);
                    return true;
                }
            }
            return super.onTransact(code, data, reply, flags);
        }

        private static class Proxy implements com.example.nft.myapplication.IMyAidlInterface {
            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中,并通过transact传递给远程服务
                    _data.writeInterfaceToken(DESCRIPTOR);
                    _data.writeString(s);
                    mRemote.transact(Stub.TRANSACTION_getInfor, _data, _reply, 0);
                    //远程服务的onTransact中处理完数据后,返回true之后,proxy就可以将远程服务的数据读出来
                    _reply.readException();
                    _result = _reply.readString();
                } finally {
                    _reply.recycle();
                    _data.recycle();
                }
                return _result;
            }

            @Override
            public int add(int a, int b) 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);
                    _data.writeInt(a);
                    _data.writeInt(b);
                    mRemote.transact(Stub.TRANSACTION_add, _data, _reply, 0);
                    _reply.readException();
                    _result = _reply.readInt();
                } finally {
                    _reply.recycle();
                    _data.recycle();
                }
                return _result;
            }
        }

        static final int TRANSACTION_getInfor = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
        static final int TRANSACTION_add = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
    }

    public java.lang.String getInfor(java.lang.String s) throws android.os.RemoteException;

    public int add(int a, int b) throws android.os.RemoteException;
}
自动生成的这个java文件,其重点内容是一个静态抽象stub类,该类是实现了 IMyInterface定义的方法并继承了Binder的类,

1 在远程服务中 new IMyInterface.Stub()就会将并把它向上转型成了IBinder,最后在onBind方法中返回回去。并在IMyInterface.Stub()的内部我们重写getInfor(String s) ,add(int a,int b)方法。

2   在本地客户端中 new ServiceConnection并实现onServiceConnected、onServiceDisconnected。在onServiceConnected中通过IMyInterface.Stub.asInterface(service)把传来的IBinder转换成了IMyInterface。然后调用getInfor,add(int a,int b)方法,传递了参数和获取从RemouteService返回的结果,并且打印了Log。

3 当本地客户端成功绑定RemouteService时,会得到一个由new IMyInterface.Stub()转型的binder,并在onServiceConnected回调中,将这个binder作为参数传递给IMyInterface.Stub.asInterface(service)就可以得到IMyInterface了,然后利用IMyInterface,来婉转的调用已经由new IMyInterface.Stub()重写的getInfor(String s) ,add(int a,int b)方法。

asInterface这个静态方法中,会对客户端传进来的binder进行一系列的判断,首先判断IBinder是不是null,如果为null就返回一个null;接着就判断传进来的IBinder是不是就在当前进程里面,如果是的话就直接返回IMyInterface,不是的话就返回IMyInterface.Stub.Proxy(obj)。直接返回的IMyInterface是实现了定义的接口方法getInfor的。因为在IMyInterface.Stub中所实现的。当然如果是在同一进程中,那么我们调用IMyInterface的方法时就是在本地调用方法,直接调用就可以了。如果没在同一进程,就会返回IMyInterface.Stub.Proxy(obj):

5 在Proxy中,首先把远程服务RemonteService连接成功返回的IBinder它的内部变量mRemote,。然后,当我们调用IMyInterface的方法的时候,其实就是调用实现IMyInterface接口的Proxy的类方法。

所以当客户端调用IMyInterface.getInfor(String s) ,其实就是调用Proxy中的getInfor,它先获取了两个Parcel对象 _data、_reply,一个是传送数据的,另一个是接受返回数据的。接着,向_data中写入了DESCRIPTOR(也就是这个类的全名),再写入传递进来的s参数。然后利用转换成本地变量binder的mRemote,将数据传递给远程服务

mRemote.transact(Stub.TRANSACTION_getInfor, _data, _reply, 0); 
这里调用了IBinder的transact方法,把数据传给远端的服务器。当数据成功传送到远程服务时,远程服务中的Stub,作为Binder子类,就会回调onTransact(),onTransact方法是在Stub的内部实现的.

6 在远程服务中的stub如果调用了onTransact就表示有数据传来,首先就会通过swicth判断是哪个方法,然后取出方法参数,调用本地实现的方法获取返回值,也就是调用new IMyInterface.Stub()重写的getInfor(String s)方法,并将返回值写入reply。最后,返回true,才会把数据发送给客户端,相反,返回false就不会把结果返回给Activity了。这里也就是说,只有返回true,Proxy中才能接受从远程服务传回的数据,也就是说可以获取到reply.readXXX的值了。

结论:

自动生成的Stub这个静态抽象方法中有:

1自身是实现IMyInterface方法的Binder子类,可以在同一进程中重写接口方法,供本地服务调用

asInterface的静态方法,是返回IMyInterface对象的,供客户端调用相应的接口方法

Proxy的内部类,是实现IMyInterface方法的一个类,供客户端调用远程服务实现的接口方法,将远程服务的binder本地化,并通过transact将参数传送给远程服务。

onTransact()回调,是stub作为binder子类的一个基本回调,供客户端传递数据成功后,使用远程服务的方法获取结果后,将结果发送给客户端

5 对于远程服务,通过new IMyInterface.Stub()实现了aidl定义的方法,并返回binder来供客户端间接的调用已实现的接口,对于客户端,通过IMyInterface.Stub.asInterface(service),利用远程服务返回的binder,获取到IMyInterface对象,并通过调用已实现的接口来获取远程服务发送的结果

第三部分 远程service的另一种写法

因为new IMyInterface.Stub()是返回binder,让service返回给客户端,所以也可以自己定义binder类,返回给客户端,主要自己定义的binder也是继承了binder并实现IMyInterface方法即可

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return new MyBinder();
    }

    private class MyBinder extends IMyAidlInterface.Stub{
        @Override
        public String getInfor(String s) throws RemoteException {
            Log.i("niuniu ", " 收到了客户端的请求");
            return "我是远程服务返回的字串";
        }

        @Override
        public int add(int a, int b) throws RemoteException {
            Log.i("niuniu ", " 收到了客户端的数据 a = " + a +"  b = " +b);
            return a+b;
        }
    }

猜你喜欢

转载自blog.csdn.net/dakaniu/article/details/79412694