初识AIDL

作者: Frank_Kivi | 来源:发表于2017-09-16 08:48 被阅读94次

    说起来AIDL,安卓开发者可能都听说过。但是真正使用过或者深入了解过的估计就不多了。本文将从一个例子出发,来简单说明AIDL的使用方法和原理。
    AIDL是用来做进程间的通信的,有个最简单的需求。现在有两个项目,需要做通信调用。第一反应可能是写接口来做回调,但这个要求两个项目必须有依赖关系。假如现在我们要求不能让他们有任何的依赖关系又该如何处理呢,答案就是要做进程间的通信,使用AIDL。
    通过上面的分析,我们也知道了,AIDL的使用是要求有两个不同的项目,其中一个项目来调用另外一个项目的方法。根据安卓Binder的规范,通过来说,调用方法的我们叫做客户端,被调用方法(即提供方法)的我们叫做服务端。
    下面我们来直接上代码,先看服务端。

    // Caculator.aidl
    package com.example.server;
    
    // Declare any non-default types here with import statements
    
    interface Caculator {
        /**
         * Demonstrates some basic types that you can use as parameters
         * and return values in AIDL.
         */
        int sum(int a, int b);
    }
    

    首先是AIDL文件,两边的必须保证完全一致,最好是复制粘贴。
    编译后会产生一个对应的代理文件。

    /*
     * This file is auto-generated.  DO NOT MODIFY.
     * Original file: D:\\IDE\\AndroidStudioProjects\\AIDL\\server\\src\\main\\aidl\\com\\example\\server\\Caculator.aidl
     */
    package com.example.server;
    
    // Declare any non-default types here with import statements
    
    public interface Caculator extends android.os.IInterface {
        /**
         * Local-side IPC implementation stub class.
         */
        public static abstract class Stub extends android.os.Binder implements com.example.server.Caculator {
            private static final java.lang.String DESCRIPTOR = "com.example.server.Caculator";
    
            /**
             * Construct the stub at attach it to the interface.
             */
            public Stub() {
                this.attachInterface(this, DESCRIPTOR);
            }
    
            /**
             * Cast an IBinder object into an com.example.server.Caculator interface,
             * generating a proxy if needed.
             */
            public static com.example.server.Caculator asInterface(android.os.IBinder obj) {
                if ((obj == null)) {
                    return null;
                }
                android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
                if (((iin != null) && (iin instanceof com.example.server.Caculator))) {
                    return ((com.example.server.Caculator) iin);
                }
                return new com.example.server.Caculator.Stub.Proxy(obj);
            }
    
            @Override
            public android.os.IBinder asBinder() {
                return this;
            }
    
            @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_sum: {
                        data.enforceInterface(DESCRIPTOR);
                        int _arg0;
                        _arg0 = data.readInt();
                        int _arg1;
                        _arg1 = data.readInt();
                        int _result = this.sum(_arg0, _arg1);
                        reply.writeNoException();
                        reply.writeInt(_result);
                        return true;
                    }
                }
                return super.onTransact(code, data, reply, flags);
            }
    
            private static class Proxy implements com.example.server.Caculator {
                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 sum(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_sum, _data, _reply, 0);
                        _reply.readException();
                        _result = _reply.readInt();
                    } finally {
                        _reply.recycle();
                        _data.recycle();
                    }
                    return _result;
                }
            }
    
            static final int TRANSACTION_sum = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
        }
    
        public int sum(int a, int b) throws android.os.RemoteException;
    }
    

    我们先来查看这个文件的结构图。


    首先它是一个继承android.os.IInterface的接口,然后接口中有咱们刚才自定义的方法,另外有一个抽象类Stub,是Binder的子类,然后实现了我们定义的接口。


    然后是Stub类,Stub类里边有一个Proxy类。下边我们来一一分析他们的方法。

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

    接口只是来定义规范的,所以在服务端我们要使用的其实是Stub类,然后在构造的时候需要传入一个Tag,DESCRIPTOR其实就是类名的全称,一个项目中是唯一的。

     /**
             * Cast an IBinder object into an com.example.server.Caculator interface,
             * generating a proxy if needed.
             */
            public static com.example.server.Caculator asInterface(android.os.IBinder obj) {
                if ((obj == null)) {
                    return null;
                }
                android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
                if (((iin != null) && (iin instanceof com.example.server.Caculator))) {
                    return ((com.example.server.Caculator) iin);
                }
                return new com.example.server.Caculator.Stub.Proxy(obj);
            }
    

    服务端在生成这个Binder对象后,客户端可以使用asInterface把得到一个对应的接口实现类,使用到了DESCRIPTOR来区分,如果没有是new的一个Proxy对象。中间涉及到ServerManager和Binder的传输,有兴趣的同学做深入了解。

     @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_sum: {
                        data.enforceInterface(DESCRIPTOR);
                        int _arg0;
                        _arg0 = data.readInt();
                        int _arg1;
                        _arg1 = data.readInt();
                        int _result = this.sum(_arg0, _arg1);
                        reply.writeNoException();
                        reply.writeInt(_result);
                        return true;
                    }
                }
                return super.onTransact(code, data, reply, flags);
            }
    

    onTransact是真正来实现方法调用和数据的传输的,首先写入标记,然后把读取到的数据进行sum运算,然后再写回去。
    最重要的来了,Proxy,刚才我们说过,返回给客户端的不是Stub,而是Proxy。

     private static class Proxy implements com.example.server.Caculator {
                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 sum(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_sum, _data, _reply, 0);
                        _reply.readException();
                        _result = _reply.readInt();
                    } finally {
                        _reply.recycle();
                        _data.recycle();
                    }
                    return _result;
                }
            }
    
            static final int TRANSACTION_sum = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
        }
    

    这里一定要注意Proxy的sum方法,大家要清楚,这个Proxy的代码是运行在客户端的,因为客户端使用asInterface转化后得到的就是Proxy。我们查看sum方法,它先把数据参数写入,然后进行传输,后边调用了 mRemote.transact,这个mRemote可以简单的认为就是Stub,然后内部走了Stub的onTransact,先读取数据,然后计算器后返回数据,中间使用的都是Binder机制的IPC通信,Proxy在接到数据后返回给调用者。
    下边我们来上客户端和服务端的代码。
    服务端

    package com.example.server;
    
    import android.app.Service;
    import android.content.Intent;
    import android.os.IBinder;
    import android.os.RemoteException;
    
    public class MyService extends Service {
        public MyService() {
        }
    
        @Override
        public IBinder onBind(Intent intent) {
            return CACULATOR;
        }
    
        private static final Caculator.Stub CACULATOR = new Caculator.Stub() {
            @Override
            public int sum(int a, int b) throws RemoteException {
                return a + b;
            }
        };
    }
    

    客户端

    package com.example.frank.myapplication;
    
    import android.app.Activity;
    import android.content.ComponentName;
    import android.content.Context;
    import android.content.Intent;
    import android.content.ServiceConnection;
    import android.os.Bundle;
    import android.os.Handler;
    import android.os.IBinder;
    import android.os.RemoteException;
    import android.widget.Toast;
    
    import com.example.client.Caculator;
    
    
    public class MainActivity extends Activity {
        private Caculator caculator;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            final int a = 1;
            final int b = 1;
            Intent intent = new Intent();
            intent.setComponent(new ComponentName("com.example.server", "com.example.server.MyService"));
            bindService(intent, new ServiceConnection() {
                @Override
                public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
                    caculator = Caculator.Stub.asInterface(iBinder);
                }
    
                @Override
                public void onServiceDisconnected(ComponentName componentName) {
                    caculator = null;
                }
            }, Context.BIND_AUTO_CREATE);
            try {
                Toast.makeText(MainActivity.this, caculator.sum(a, b) + "", Toast.LENGTH_SHORT).show();
            } catch (Exception e) {
                e.printStackTrace();
            }
            new Handler().postDelayed(new Runnable() {
                @Override
                public void run() {
                    try {
                        Toast.makeText(MainActivity.this, caculator.sum(a, b) + "", Toast.LENGTH_SHORT).show();
                    } catch (RemoteException e) {
                        e.printStackTrace();
                    }
                }
            }, 5000);
        }
    }
    

    两点需要注意的:
    1,binderService是异步方法,所以尽量早的调用,并且在使用的时候要注意非空判断。
    2,新版本的启动服务的方法不支持隐式调用,注意写法。
    好了,对AIDL的简单使用相信大家都有一定的了解了,但是Binder机制的IPC通信内容非常多,希望后续能够再来分享。

    相关文章

      网友评论

        本文标题:初识AIDL

        本文链接:https://www.haomeiwen.com/subject/xgtysxtx.html