Andrid AIDL简介和使用

零.前言

本片文章主要介绍Android AIDL的概念和使用,着重介绍AIDL的使用。

一.基本概念

什么是Binder:简单的来讲,我们可以将Binder看成Android进程间通信的一种方式,是Android的特性之一。

什么是ALDL:AIDL ( Android Interface Definition Language ) Android接口定义语言。AIDL是一种编程规范,用于生成在Android设备上两个进程通信的代码,内部是使用Binder实现的。

二.AIDL支持的数据类型

  1. Java基本数据类型:boolean char byte int long float double string
  2. Intent,Bundle,Bitmap,List和Map(集合存储的元素必须是AIDL支持的类型,服务端接收的实体必须是ArrayList和HashMap)
  3. 其他AIDL接口
  4. 实现Parcelable接口的可序列化引用类型

三.AIDL的使用

1.新建AIDL文件

工程Main目录下新建和java目录平级的aidl目录——新建包名——新建AIDL文件

示例如下:

image

*PluginData.aidl:

  • 这里需要注意:在AIDL中使用的数据类型,除了基本数据、list和Map其他类型必须使用import关键字导入
package com.li.pluginapp;

import com.li.pluginapp.TestData;

interface PluginData {

    String conversionJsonData(String formJsonData);
    /**
     * 除了基本数据类型,其他类型的参数都需要标上方向类型:in(输入), out(输出), inout(输入输出)
     */
    void addTestData(in TestData data);

    List getTestData();
}
2.声明Parcelable对象
  • 自定义的数据类型,必须实现Parcelable接口
  • 自定义的数据类型,必须创建一个和实体类同名的映射 aidl 文件,同时声明为parcelable类型

*TestData.java

package com.li.pluginapp;

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

public class TestData implements Parcelable {
    private int id;

    private String jsonString;

    protected TestData(Parcel in) {
        id = in.readInt();
        jsonString = in.readString();
    }

    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 getJsonString() {
        return jsonString;
    }

    public void setJsonString(String jsonString) {
        this.jsonString = jsonString;
    }

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

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeInt(id);
        dest.writeString(jsonString);
    }

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

*TestData.aidl

  • 注意:这个TestData.aidl的包名必须和实体类一致
package com.li.pluginapp;

parcelable TestData;
3.服务端
  1. 创建进程通信的Service用来监听客户端进程的连接请求
  2. 生成Binder对象,实现aidl接口定义的方法
  3. onBinder方法返回Binder对象

*ServerService.java

package com.li.pluginapp;

import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;
import android.support.annotation.Nullable;
import android.util.Log;

import java.util.ArrayList;
import java.util.List;

/**
 * 服务端Service
 */

public class ServerService extends Service {

    private ArrayList mData = new ArrayList<>();

    private PluginData.Stub mBinder = new PluginData.Stub() {
        @Override
        public String conversionJsonData(String formJsonData) throws RemoteException {
            return "已收到传送的JSON数据: " + formJsonData;
        }

        @Override
        public void addTestData(TestData data) throws RemoteException {
            mData.add(data);
            Log.d("服务器:addTestData",data.toString());
        }

        @Override
        public List getTestData() throws RemoteException {
            Log.d("服务器:getTestData","");
            return mData;
        }
    };

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

别忘了在manifest中注册,隐式调用配置下intent-filter

 
            
                
                
            
        
4.客户端
  1. 如果在不同的工程中,需要将aidl目录下所有文件复制一份到新工程中(服务端一样,包名需要一致)
  2. 自定义数据类型复制一份(服务端一样,包名需要一致)
  3. 调用bindService建立连接获得Binder对象
  4. 将Binder对象转换成对应aidl所属的类型,之后就可以调用aidl接口定义的方法了
Intent intent = new Intent("com.li.pluginapp.ServerService");
        intent.setPackage("com.li.pluginapp");
        bindService(intent, new ServiceConnection() {
            @Override
            public void onServiceConnected(ComponentName name, IBinder service) {
                try {
                    iPluginDataManager = PluginData.Stub.asInterface(service);
                    for (int i = 0; i < 10; i++) {
                        iPluginDataManager.addTestData(new TestData(i, "测试数据" + i));
                    }
                    List testData = iPluginDataManager.getTestData();
                    Log.d("客户端发送的消息:", testData.toString());
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
            }

            @Override
            public void onServiceDisconnected(ComponentName name) {

            }
        }, BIND_AUTO_CREATE);
  • 这里就不贴完整的代码,在另一工程中,所以需要隐式启动Intent,Android5.0之后需要指定包名转为显式调用,不然会报错
  • onServiceConnected建立连接回调方法中会传递Binder对象,将其转换从aidl对象保存,之后就可以通过此aidl对象调用相应的方法了

这里可以看下服务端的打印日志,循环添加了10个数据:

07-21 16:08:10.212 28746-28758/com.li.pluginapp D/服务器:addTestData: TestData{id=0, jsonString='测试数据0'}
07-21 16:08:10.213 28746-28759/com.li.pluginapp D/服务器:addTestData: TestData{id=1, jsonString='测试数据1'}
07-21 16:08:10.213 28746-28815/com.li.pluginapp D/服务器:addTestData: TestData{id=2, jsonString='测试数据2'}
07-21 16:08:10.213 28746-28758/com.li.pluginapp D/服务器:addTestData: TestData{id=3, jsonString='测试数据3'}
07-21 16:08:10.213 28746-28759/com.li.pluginapp D/服务器:addTestData: TestData{id=4, jsonString='测试数据4'}
07-21 16:08:10.214 28746-28815/com.li.pluginapp D/服务器:addTestData: TestData{id=5, jsonString='测试数据5'}
07-21 16:08:10.214 28746-28758/com.li.pluginapp D/服务器:addTestData: TestData{id=6, jsonString='测试数据6'}
07-21 16:08:10.216 28746-28759/com.li.pluginapp D/服务器:addTestData: TestData{id=7, jsonString='测试数据7'}
07-21 16:08:10.216 28746-28815/com.li.pluginapp D/服务器:addTestData: TestData{id=8, jsonString='测试数据8'}
07-21 16:08:10.217 28746-28758/com.li.pluginapp D/服务器:addTestData: TestData{id=9, jsonString='测试数据9'}

可以看到,Activity 与 另外一个进程的 Service 通信成功了

你可能感兴趣的:(Andrid AIDL简介和使用)