胖蔡说技术
随便扯扯

AIDL 消息通信

AIDL(Android Interface Definition Language) 即Android接口定义语言,是用来实现不同进程间通信的。AIDL同时也是另外两种进程通信方式Messager和ContentProvider的底层实现方法,所以了解aidl的使用显得尤为重要。点击获取 github示例源码。

操作步骤

AIDL通信的实现是需要客户端和服务端的配合,如下介绍如何实现一个简单的AIDL通信。

创建aidl文件

aidl文件是客户端请求服务端操作获取交互信息的基础,只需要在Android Studio的 src/main
目录下创建一个aidl目录(或者也可以在gradle中指定aidl位置),然后在该目录下创建一个aidl文件,android studio会自动生成一个包名并将aidl放在该包下。

    // ITestInterface.aidl
    package com.kubo.aidlproject;
    import com.kubo.aidlproject.TestData;

    // Declare any non-default types here with import statements
    //设置客户端调用的接口
    interface ITestInterface {
        /**
         * Demonstrates some basic types that you can use as parameters
         * and return values in AIDL.
         */
       void sendTest(in TestData testData);


       void sendTest2(out TestData testData,int a);

       void sendTest3(inout TestData testData,String a);

    }

如上所示,aidl支持如下如下数据传递:

  • Java所有的基本数据类型(int、long、short等)
  • String和CharSequence
  • List 子项中也必须是aidl支持的类型
  • Map 子项中也必须是aidl支持的类型
  • AIDL aidl本省也可作为传递的类型
  • Parcelable 所有实现Parcelable接口的对象

AIDL中除了基本类型外其他类型需要设置数据流的方向( inout , inout ):

  • in in 代表为输入流方向,即client可修改,service端修改无效
  • out out 代表输出流方向,即service端可修改,client修改无效
  • inout inout代表双向流,即service和client端均可对其进行修改

如上,创建的aidl需要传递的参数TestData:

    package com.kubo.aidlproject;

    import android.os.Parcel;
    import android.os.Parcelable;

    /**
     *
     * 测试数据序列化
     * @author hfcai
     */
    public class TestData implements Parcelable {
        private int id;
        private String name;

        @Override
        public String toString() {
            return "TestData{" +
                    "id=" + id +
                    ", name='" + name + '\'' +
                    ", tips='" + tips + '\'' +
                    ", can=" + can +
                    '}';
        }

        private String tips;
        private boolean can;

        public TestData(){}

        public TestData(int id, String name, String tips, boolean can) {
            this.id = id;
            this.name = name;
            this.tips = tips;
            this.can = can;
        }

        protected TestData(Parcel in) {
            id = in.readInt();
            name = in.readString();
            tips = in.readString();
            can = in.readByte()!=0;

        }


        public void readFromParcel(Parcel in) {
            id = in.readInt();
            name = in.readString();
            tips = in.readString();
            can = in.readByte()!=0;
        }

        @Override
        public void writeToParcel(Parcel dest, int flags) {
            dest.writeInt(id);
            dest.writeString(name);
            dest.writeString(tips);
            dest.writeByte((byte) (can?1:0));
        }

        @Override
        public int describeContents() {
            return 0;
        }

        public static final Creator<TestData> CREATOR = new Creator<TestData>() {
            @Override
            public TestData createFromParcel(Parcel in) {
                return new TestData(in);
            }

            @Override
            public TestData[] newArray(int size) {
                return new TestData[size];
            }
        };

        public int getId() {
            return id;
        }

        public void setId(int id) {
            this.id = id;
        }

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public boolean isCan() {
            return can;
        }

        public void setCan(boolean can) {
            this.can = can;
        }

        public String getTips() {
            return tips;
        }

        public void setTips(String tips) {
            this.tips = tips;
        }


    }

同时还需要在aidl中声明一个parcelable对象:

    //TestData .aidl
    package com.kubo.aidlproject;

    // Declare any non-default types here with import statements
    parcelable TestData;

创建完aidl后,android sdk工具可将其自动转化为对应的继承I Interface
的接口,其实也就是生成一个binder的过程,如上aidl对应的接口如下:

    //
    // Source code recreated from a .class file by IntelliJ IDEA
    // (powered by Fernflower decompiler)
    //

    package com.kubo.aidlproject;

    import android.os.Binder;
    import android.os.IBinder;
    import android.os.IInterface;
    import android.os.Parcel;
    import android.os.RemoteException;

    public interface ITestInterface extends IInterface {
        void sendTest(TestData var1) throws RemoteException;

        void sendTest2(TestData var1, int var2) throws RemoteException;

        void sendTest3(TestData var1, String var2) throws RemoteException;

        public abstract static class Stub extends Binder implements ITestInterface {
            private static final String DESCRIPTOR = "com.kubo.aidlproject.ITestInterface";
            static final int TRANSACTION_sendTest = 1;
            static final int TRANSACTION_sendTest2 = 2;
            static final int TRANSACTION_sendTest3 = 3;

            public Stub() {
                this.attachInterface(this, "com.kubo.aidlproject.ITestInterface");
            }

            public static ITestInterface asInterface(IBinder obj) {
                if (obj == null) {
                    return null;
                } else {
                    IInterface iin = obj.queryLocalInterface("com.kubo.aidlproject.ITestInterface");
                    return (ITestInterface)(iin != null && iin instanceof ITestInterface ? (ITestInterface)iin : new ITestInterface.Stub.Proxy(obj));
                }
            }

            public IBinder asBinder() {
                return this;
            }

            public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
                String descriptor = "com.kubo.aidlproject.ITestInterface";
                TestData _arg0;
                switch(code) {
                case 1:
                    data.enforceInterface(descriptor);
                    if (0 != data.readInt()) {
                        _arg0 = (TestData)TestData.CREATOR.createFromParcel(data);
                    } else {
                        _arg0 = null;
                    }

                    this.sendTest(_arg0);
                    reply.writeNoException();
                    return true;
                case 2:
                    data.enforceInterface(descriptor);
                    _arg0 = new TestData();
                    int _arg1 = data.readInt();
                    this.sendTest2(_arg0, _arg1);
                    reply.writeNoException();
                    if (_arg0 != null) {
                        reply.writeInt(1);
                        _arg0.writeToParcel(reply, 1);
                    } else {
                        reply.writeInt(0);
                    }

                    return true;
                case 3:
                    data.enforceInterface(descriptor);
                    if (0 != data.readInt()) {
                        _arg0 = (TestData)TestData.CREATOR.createFromParcel(data);
                    } else {
                        _arg0 = null;
                    }

                    String _arg1 = data.readString();
                    this.sendTest3(_arg0, _arg1);
                    reply.writeNoException();
                    if (_arg0 != null) {
                        reply.writeInt(1);
                        _arg0.writeToParcel(reply, 1);
                    } else {
                        reply.writeInt(0);
                    }

                    return true;
                case 1598968902:
                    reply.writeString(descriptor);
                    return true;
                default:
                    return super.onTransact(code, data, reply, flags);
                }
            }

            private static class Proxy implements ITestInterface {
                private IBinder mRemote;

                Proxy(IBinder remote) {
                    this.mRemote = remote;
                }

                public IBinder asBinder() {
                    return this.mRemote;
                }

                public String getInterfaceDescriptor() {
                    return "com.kubo.aidlproject.ITestInterface";
                }

                public void sendTest(TestData testData) throws RemoteException {
                    Parcel _data = Parcel.obtain();
                    Parcel _reply = Parcel.obtain();

                    try {
                        _data.writeInterfaceToken("com.kubo.aidlproject.ITestInterface");
                        if (testData != null) {
                            _data.writeInt(1);
                            testData.writeToParcel(_data, 0);
                        } else {
                            _data.writeInt(0);
                        }

                        this.mRemote.transact(1, _data, _reply, 0);
                        _reply.readException();
                    } finally {
                        _reply.recycle();
                        _data.recycle();
                    }

                }

                public void sendTest2(TestData testData, int a) throws RemoteException {
                    Parcel _data = Parcel.obtain();
                    Parcel _reply = Parcel.obtain();

                    try {
                        _data.writeInterfaceToken("com.kubo.aidlproject.ITestInterface");
                        _data.writeInt(a);
                        this.mRemote.transact(2, _data, _reply, 0);
                        _reply.readException();
                        if (0 != _reply.readInt()) {
                            testData.readFromParcel(_reply);
                        }
                    } finally {
                        _reply.recycle();
                        _data.recycle();
                    }

                }

                public void sendTest3(TestData testData, String a) throws RemoteException {
                    Parcel _data = Parcel.obtain();
                    Parcel _reply = Parcel.obtain();

                    try {
                        _data.writeInterfaceToken("com.kubo.aidlproject.ITestInterface");
                        if (testData != null) {
                            _data.writeInt(1);
                            testData.writeToParcel(_data, 0);
                        } else {
                            _data.writeInt(0);
                        }

                        _data.writeString(a);
                        this.mRemote.transact(3, _data, _reply, 0);
                        _reply.readException();
                        if (0 != _reply.readInt()) {
                            testData.readFromParcel(_reply);
                        }
                    } finally {
                        _reply.recycle();
                        _data.recycle();
                    }

                }
            }
        }
    }

创建服务

如上完成了aidl的创建后还需要创建提供服务的服务类,从而实现提供服务的目的,如下:

    public class AIDLService extends Service {
        private static final String TAG = "AIDLService";
        ITestAidlStub stub = new ITestAidlStub();
        @Override
        public void onCreate() {
            super.onCreate();
            Log.e(TAG,"-----------创建AIDL服务-------------");
        }

        @Override
        public int onStartCommand(Intent intent, int flags, int startId) {
            Log.e(TAG,"----------------onStartCommand-----------------");
            return super.onStartCommand(intent, flags, startId);
        }


        @Override
        public void onDestroy() {
            Log.e(TAG,"----------------------onDestroy---------------");
            super.onDestroy();
        }

        @Override
        public IBinder onBind(Intent intent) {
            Log.e(TAG,"----------------------onBind---------------");
            return stub;
        }
    }

    public class ITestAidlStub extends ITestInterface.Stub {
        private static final String TAG = "ITestAidlStub";


        @Override
        public void sendTest(TestData testData) throws RemoteException {
            Log.e(TAG,"sendTest,testData is in:"+testData.toString());
            testData.setName("test_service");

        }

        @Override
        public void sendTest2(TestData testData, int a) throws RemoteException {
            Log.e(TAG,"sendTest,testData is out:"+testData.toString());
            testData.setName("test_service");

        }

        @Override
        public void sendTest3(TestData testData, String a) throws RemoteException {
            Log.e(TAG,"sendTest,testData is inout:"+testData.toString());
            testData.setName("test_service");

        }
    }

完成服务的编写还得需要在manifest中注册该服务:

    
        <service android:name=".AIDLService"
                android:exported="true"
                android:process=":test"/>

由于本次是为了测试多进程通信,且是在同一个app中,所以就需要我们为这个服务单独开一个进程

请求服务

服务创建好后,我们就可以在我们app的主进程中创建一个服务连接并通过bindService绑定服务了。

    public class MainActivity extends AppCompatActivity {

        ITestInterface iTestInterface;

        /**
         * 连接服务
         */
        private ServiceConnection serviceConnection = new ServiceConnection() {

            @Override
            public void onServiceConnected(ComponentName name, IBinder service) {
                iTestInterface = ITestAidlStub.asInterface(service);
                Log.e("MainActivity","onServiceConnected");

            }

            /**
             * service异常终止
             * @param name
             */
            @Override
            public void onServiceDisconnected(ComponentName name) {
                iTestInterface = null;
                Log.e("MainActivity","onServiceDisconnected");

            }
        };


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


        public void onClick(View view){
            TestData testData = new TestData(0,"hfcai","注意提示!",true);
            switch (view.getId()){
                case R.id.bind:
                    //绑定服务
                   Intent intent = new Intent(this,AIDLService.class);
                   bindService(intent,serviceConnection, Context.BIND_AUTO_CREATE);
                    break;

                case R.id.send_in:
                    //发送测试数据
                    if (iTestInterface!=null){
                        try {
                            iTestInterface.sendTest(testData);
                            Log.e("in","testData:"+testData.toString());
                        } catch (RemoteException e) {
                            e.printStackTrace();
                            Log.e("in error",e.getMessage());
                        }
                    }else {
                        Toast.makeText(this,"连接服务失败!",Toast.LENGTH_SHORT).show();
                    }
                    break;
                case R.id.send_out:
                    //发送测试数据
                    if (iTestInterface!=null){

                        try {
                            iTestInterface.sendTest2(testData,0);
                            Log.e("out","testData:"+testData.toString());
                        } catch (RemoteException e) {
                            e.printStackTrace();
                            Log.e("out error",e.getMessage());
                        }
                    }else {
                        Toast.makeText(this,"连接服务失败!",Toast.LENGTH_SHORT).show();
                    }
                    break;
                case R.id.send_inout:
                    //发送测试数据
                    if (iTestInterface!=null){
                        try {
                            iTestInterface.sendTest3(testData,"inout");
                            Log.e("inout","testData:"+testData.toString());
                        } catch (RemoteException e) {
                            e.printStackTrace();
                            Log.e("inout error",e.getMessage());
                        }
                    }else {
                        Toast.makeText(this,"连接服务失败!",Toast.LENGTH_SHORT).show();
                    }
                    break;
                default:
                    break;
            }
        }
    }

这样就完成了一个简单的Demo实现。

赞(0) 打赏
转载请附上原文出处链接:胖蔡说技术 » AIDL 消息通信
分享到: 更多 (0)

请小编喝杯咖啡~

支付宝扫一扫打赏

微信扫一扫打赏