IPC的实现:AIDL

概述

AIDL是Android Interface Definition Language的缩写,在某种意义上讲,AIDL其实是一个模板,有规范和约束的作用。实际上起作用的是根据AIDL而生产的实例代码。
AIDL与Java语音的接口十分的相似,也它也有一些几点特点:

  1. AIDL支持的数据格式支持8大基本数据类型(byte、char、short、int、long、float、double、boolean,String,CharSequence),支持的空间数据结构有List和Map。
  2. 数据流向标记。in、out、inout。in 表示数据只能由客户端流向服务端, out 表示数据只能由服务端流向客户端,而 inout 则表示数据可在服务端与客户端之间双向流通。
  3. 手动导包。
    在Android中,跨进程通信采用的Binder机制,而基于Binder来实现跨进程的方式通常是采用AIDL和Massenger。
    两者的关系是:AIDL是基于Messenger,而Messenger是基于Binder的。
    关于更多关于Binder机制的知识可参看《IPC机制

AIDL具体实现

在AS中添加.aidl文件:

  1. 首先定义服务接口,IMyAidlInterface.aidl:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    // IMyAidlInterface.aidl
    package com.zhouk.soft.mystudio;
    //引用数据类型
    import com.zhouk.soft.mystudio.entity.TestAidlBean;
    interface IMyAidlInterface {

    String AIDL_Service();

    void addMyAidlBean(in TestAidlBean bean);//添加Bean到List里

    List<TestAidlBean> getList();//获取List
    }
  2. 定义引用类型,TestAidlBean.aidl:

    1
    2
    3
    4
    // TestAidlBean.aidl
    package com.zhouk.soft.mystudio.entity;

    parcelable TestAidlBean;

注意,aidl引用数据类型必须与Java中对应的Bean相同包名

  1. AIDL文件添加完成后Make Project一下。会根据IMyAidlInterface.aidl来生成IMyAidlInterface.java文件。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    public interface IMyAidlInterface extends android.os.IInterface {
    /**
    * Binder对象
    */
    public static abstract class Stub extends android.os.Binder implements com.zhouk.soft.mystudio.IMyAidlInterface {

    /**
    * Cast an IBinder object into an com.zhouk.soft.mystudio.IMyAidlInterface interface,
    * generating a proxy if needed.
    */
    public static com.zhouk.soft.mystudio.IMyAidlInterface asInterface(android.os.IBinder obj) {
    // ... ...
    return new com.zhouk.soft.mystudio.IMyAidlInterface.Stub.Proxy(obj);
    }

    @Override
    public android.os.IBinder asBinder() {
    return this;
    }
    //收到Binder驱动通知后,Server 进程通过回调Binder对象onTransact()进行数据解包 & 调用目标方法
    @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_AIDL_Service: {
    data.enforceInterface(DESCRIPTOR);
    java.lang.String _result = this.AIDL_Service();
    reply.writeNoException();
    reply.writeString(_result);
    return true;
    }
    case TRANSACTION_addMyAidlBean: {
    data.enforceInterface(DESCRIPTOR);
    com.zhouk.soft.mystudio.entity.TestAidlBean _arg0;
    if ((0 != data.readInt())) {
    _arg0 = com.zhouk.soft.mystudio.entity.TestAidlBean.CREATOR.createFromParcel(data);
    } else {
    _arg0 = null;
    }
    this.addMyAidlBean(_arg0);
    reply.writeNoException();
    return true;
    }
    case TRANSACTION_getList: {
    data.enforceInterface(DESCRIPTOR);
    java.util.List<com.zhouk.soft.mystudio.entity.TestAidlBean> _result = this.getList();
    reply.writeNoException();
    reply.writeTypedList(_result);
    return true;
    }
    }
    //将结算结果返回 到Binder驱动
    return super.onTransact(code, data, reply, flags);
    }

    // 1. Binder驱动根据 代理对象 沿原路 将结果返回 并通知Client进程获取返回结果
    // 2. 通过代理对象 接收结果(之前被挂起的线程被唤醒)
    private static class Proxy implements com.zhouk.soft.mystudio.IMyAidlInterface {//mRemote.transact()
    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 AIDL_Service() throws android.os.RemoteException {
    // ... ...
    mRemote.transact(Stub.TRANSACTION_AIDL_Service, _data, _reply, 0);
    _reply.readException();
    _result = _reply.readString();
    // ... ...
    return _result;
    }

    @Override
    public void addMyAidlBean(com.zhouk.soft.mystudio.entity.TestAidlBean bean) throws android.os.RemoteException {
    // ... ...
    mRemote.transact(Stub.TRANSACTION_addMyAidlBean, _data, _reply, 0);
    _reply.readException();
    // ... ...
    }

    @Override
    public java.util.List<com.zhouk.soft.mystudio.entity.TestAidlBean> getList() throws android.os.RemoteException {
    // ... ...
    mRemote.transact(Stub.TRANSACTION_getList, _data, _reply, 0);
    _reply.readException();
    _result = _reply.createTypedArrayList(com.zhouk.soft.mystudio.entity.TestAidlBean.CREATOR);
    // ... ...
    return _result;
    }
    }
    // ... ...
    }

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

    public void addMyAidlBean(com.zhouk.soft.mystudio.entity.TestAidlBean bean) throws android.os.RemoteException;

    public java.util.List<com.zhouk.soft.mystudio.entity.TestAidlBean> getList() throws android.os.RemoteException;
    }
  2. 定义进程服务

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    /**
    * Created by ZhouKang on 2018/4/14
    * 多进程,Server角色
    */
    public class TestServerService extends Service {

    private static final String TAG = "服务TestServerService";
    private List<TestAidlBean> listBean;

    @Override
    public IBinder onBind(Intent intent) {
    Log.e(TAG, "已开启service进程服务");
    return myAidlInterface;
    }

    @Override
    public boolean onUnbind(Intent intent) {
    return super.onUnbind(intent);
    }

    @Override
    public void onCreate() {
    super.onCreate();
    listBean = new ArrayList<>();
    }

    IMyAidlInterface.Stub myAidlInterface = new IMyAidlInterface.Stub() {
    @Override
    public String AIDL_Service() throws RemoteException {
    return "这是一条来自Service的消息";
    }

    @Override
    public void addMyAidlBean(TestAidlBean bean) throws RemoteException {
    listBean.add(bean);
    Log.e(TAG, "已添加来自客户端的Bean");
    }

    @Override
    public List<TestAidlBean> getList() throws RemoteException {
    return listBean;
    }
    };

    }

还要再AndroidManifest中注册一下,利用android:process为服务开启新的进程

1
2
3
4
5
6
7
8
<service
android:name=".service.TestServerService"
android:process=":remote">
<intent-filter>
<action android:name="com.zhouk.soft.mystudio.service.TestServerService"/>
<!--<action android:name="scut.carson_ho.service_server.AIDL_Service1"/>-->
</intent-filter>
</service>

  1. 在应用主进程的活动中开启进程服务

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    private static final String TAG = "客户端TestClientActivity";

    private IMyAidlInterface ser;

    private ServiceConnection mServiceConnection = new ServiceConnection() {
    @Override
    public void onServiceConnected(ComponentName name, IBinder service) {
    ser = IMyAidlInterface.Stub.asInterface(service);
    if (ser != null) {
    try {
    Log.e(TAG, ser.AIDL_Service());
    Toast.makeText(TestClientActivity.this, ser.AIDL_Service(), Toast.LENGTH_LONG).show();
    } catch (RemoteException e) {
    e.printStackTrace();
    }
    }
    }

    @Override
    public void onServiceDisconnected(ComponentName name) {

    }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    Log.e(TAG, "开始连接其他进程的服务...");
    Intent intent = new Intent("com.zhouk.soft.mystudio.service.TestServerService");

    //需要通过setPackage()方法指定包名
    intent.setPackage(getPackageName());

    //绑定服务,传入intent和ServiceConnection对象
    boolean isS = bindService(intent, mServiceConnection, Context.BIND_AUTO_CREATE);
    Log.e(TAG, "是否连接成功:"+isS);
    findViewById(R.id.btn).setOnClickListener(v -> {//往服务进程中添加Bean数据
    try {
    ser.addMyAidlBean(new TestAidlBean(123456, "name1"));
    } catch (RemoteException e) {
    e.printStackTrace();
    }
    });
    findViewById(R.id.btn2).setOnClickListener(v -> {//获取服务进程中的List数据
    if (ser != null) {
    try {
    for (int i = 0; i < ser.getList().size(); i++) {
    Log.e(TAG, "列表数据" + i + ":--->" + ser.getList().get(i).getName());
    }
    } catch (RemoteException e) {
    e.printStackTrace();
    }
    }
    });
    }
  2. 结果
    客户端:

    服务端:

    客户端:

总结

主要介绍了AIDL基于C/S的实现操作。日常开发中使用多进程的场景并不多见,但在有些地方例如音视频开发中能起到十分关键的作用,掌握基础的多进程开发知识还是十分有必要的。