AIDL 消息通信

  • 操作步骤
    • 创建aidl文件
    • 创建服务
    • 请求服务

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

本案例可在 Github 获取到Demo源码。

操作步骤

AIDL通信的实现是需要客户端和服务端的配合,具体的实现过程如下:

创建aidl文件

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

// ITestInterface.aidlpackage 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 CREATOR = new Creator() {        @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 .aidlpackage com.kubo.aidlproject;// Declare any non-default types here with import statementsparcelable TestData;

创建完aidl后,android sdk工具可将其自动转化为对应的继承IInterface的接口,其实也就是生成一个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中注册该服务:

    

由于本次是为了测试多进程通信,且是在同一个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实现。

更多相关文章

  1. tcping测试服务器TCP端口
  2. Android(安卓)进程间通讯之通过Intent+bundle实现跨进程通讯
  3. 详解Android提交数据到服务器的两种方式四种方法
  4. 模拟器中加载和使用SDCard卡
  5. Android(安卓)Service 的一些笔记
  6. Android客户端和服务器端数据交互的第二种方法
  7. 最全面的Android(安卓)Studio使用教程
  8. 使用TestProject Python SDK创建移动Appium测试
  9. Android(安卓)弹出式布局之Dialog源码分析

随机推荐

  1. Android BLE学习(二): Android与51822蓝牙模
  2. Android 一共有多少种动画?准确告诉你!
  3. android matrix使用和详细说明
  4. Android中HTTP请求中文乱码解决办法
  5. Android 自定义 spinner样式
  6. Android studio菜鸟开发————Radiogro
  7. 【Android】v7包Dialog使用
  8. android menu.addIntentOptions 添加动态
  9. 总结android中的.gradle文件写法及含义
  10. 精通Android3笔记--第十一章