Android AIDL

Android AIDL

AIDL的中文名是Android接口定义语言,用来实现进程之间的数据的共享传递。

AIDL支持的数据类型

基本数据类型(int、long、char、boolean、double等);
String和CharSequence;
List:只支持ArrayList,里面的每个元素都必须能够被AIDL支持;
Map:只支持HashMap,里面的每个元素都必须能够被AIDL支持;
Parcelable:所有实现了Parcelable接口的对象;
AIDL:所有的AIDL接口本身也可以在AIDL文件中使用。
除此之外,自定义的Parcelable对象和AIDL对象必须要显式import进来

AIDL接口的创建

需要创建一个包含.aidl后缀的文件,在其中声明一些接口

// IService.aidl
package com.apps.ipc;

// Declare any non-default types here with import statements
import com.apps.request.GetAppDetailRequest;
import com.apps.ipc.ICallback;

interface IService {
    /**
     * Demonstrates some basic types that you can use as parameters
     * and return values in AIDL.
     */
    /**
    void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,
            double aDouble, String aString);
    */

    int getAppDetail(in GetAppDetailRequest params,ICallback callback);

}
// ICallback.aidl
package com.apps.ipc;

// Declare any non-default types here with import statements
import android.os.Bundle;

interface ICallback {
    void onResult(in Bundle result);

    void onError(String code,String desc);
}

如果AIDL文件中引用到了自定义的Parcelable对象,必须要建一个与其同名的AIDL文件,并在其中声明为Parcelable类型

// IGetAppDetailRequest.aidl
package com.apps.request;

// Declare any non-default types here with import statements

parcelable GetAppDetailRequest;

注:

AIDL中除了基本数据类型,其他类型的参数必须标上方向:in、out或inout
in表示输入型参数
out表示输出型参数
inout表示输入输出参数

远程服务端Service的实现

首先需要对服务端的AIDL接口进行实现,然后在Service的onBind方法将其返回

public class IPCService extends Service {

    private ServiceStub serviceStub;

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

    @Override
    public void onCreate() {
        super.onCreate();
        serviceStub = new ServiceStub(this);
    }
}
public class ServiceStub extends IService.Stub {
    private Context context;

    public ServiceStub(Context context){
        this.context = context;
    }

    public ServiceStub() {
        super();
    }

    @Override
    public int getAppDetail(GetAppDetailRequest params, ICallback callback) throws RemoteException {
        App app = params.getApp();
        if (null == app || null == callback){
            return  Constant.AIDL_PARAMS_ERROR;
        }

        String id = app.getId();
        String version = app.getVersion();
        if (TextUtils.isEmpty(id) || TextUtils.isEmpty(version)){
            return Constant.AIDL_PARAMS_ERROR;
        }
        getAppDetailFromNetWork(id,version,callback);
        return Constant.AIDL_SUCCESS;
    }

    //模拟从网络获取数据
    private void getAppDetailFromNetWork(String id,String version,ICallback callback) throws RemoteException{
        //假设id为48,version为01.00.01能获得正确数据
        String app_id = "48";
        String app_version = "01.00.01";
        if (id.equals(app_id) && version.equals(app_version)){
            Bundle bundle = new Bundle();
            bundle.putParcelable(Constant.CALLBACK_KEY,newAppDetailResult(id,version));
            callback.onResult(bundle);
        }else{
            callback.onError(Constant.CALLBACK_ERROR_CODE,Constant.CALLBACK_ERROR_DESC);
        }
    }

    private GetAppDetailResult newAppDetailResult(String id, String version){
        AppDetail appDetail = new AppDetail();
        App app = new App(id,version);
        appDetail.setApp(app);
        appDetail.setDesc("a apk about aidl");
        appDetail.setDownloadTimes(48);
        appDetail.setName("ipc");
        GetAppDetailResult getAppDetailResult = new GetAppDetailResult();
        getAppDetailResult.setAppDetail(appDetail);
        return  getAppDetailResult;
    }

}

注:

由于AIDL方法是在服务端的Binder线程池执行,因此当多个客户端同时访问时,会存在多线程操作,所以需要在AIDL方法处理线程同步。

在AndroidManifest.xml文件中需要对Service进行配置

<service android:name=".IPCService"
         android:enabled="true">
         <intent-filter>
              <action android:name="com.apps.ipc.IPCService"></action>
         </intent-filter>
</service>

客户端的实现

服务端在编译后,会在app/build/generated/source/debug下生成对应AIDL接口的java文件,需要将其以及使用到的相关的Java类一并拷贝到客户端工程,必须确保服务端与客户端这些类的包名,否则服务端客户端无法正确反序列化对方传送的数据,造成程序无法正常运行。

img_1.png
img_2.png

绑定远程服务端

通过Context的bindService方法对远程服务端进行绑定,intent设置包名是为了解决Android5.0之后需要显示调用服务的问题。

private void bindService(){
    String action = "com.apps.ipc.IPCService";
    String packageName = "com.apps.ipc";
    Intent intent = new Intent(action);
    intent.setPackage(packageName);
    bindService(intent,connection, Context.BIND_AUTO_CREATE);
}

ServiceConnection用于处理客户端与服务端的连接、断开处理。当绑定服务成功后会回调执行onServiceConnected方法,表示已经连接上服务端,然后将服务端返回的Binder对象转换成AIDL接口,之后就可以通过这个接口去调用服务端的方法。当服务端因异常或者主动断开后,会执行onServiceDisConnected方法,表示已经断开连接。

private IService service;

private ServiceConnection connection = new ServiceConnection() {
    @Override
    public void onServiceConnected(ComponentName name, IBinder service) {
        MainActivity.this.service = IService.Stub.asInterface(service);
        result.setText("Service is connected");
    }

    @Override
    public void onServiceDisconnected(ComponentName name) {
        MainActivity.this.service = null;
        result.setText("Service is disconnected");
    }
 };

private ICallback.Stub callback = new ICallback.Stub(){
    @Override
    public IBinder asBinder() {
        return super.asBinder();
    }

    @Override
    public void onResult(Bundle bundle) throws RemoteException {
        bundle.setClassLoader(GetAppDetailResult.class.getClassLoader());
        GetAppDetailResult getAppDetailResult = bundle.getParcelable(Constant.CALLBACK_KEY);
        AppDetail appDetail = getAppDetailResult.getAppDetail();
        App app = appDetail.getApp();
        //定义了一个TextView用于显示结果
        result.setText("id:" + app.getId() + ",version:" + app.getVersion() + ",name:" + appDetail.getName()
                    + ",desc:" + appDetail.getDesc() + ",downlaodTimes:" + appDetail.getDownloadTimes());

    }

    @Override
    public void onError(String code, String desc) throws RemoteException {
        result.setText("error:" + code + ",message:" + desc);
    }
};

private void getAppDetail(String id,String version){
    if (null != service){
        GetAppDetailRequest getAppDetailRequest = new GetAppDetailRequest();
        getAppDetailRequest.setApp(new App(id,version));
        try {
            int ret = service.getAppDetail(getAppDetailRequest,callback);
            if (ret == Constant.AIDL_PARAMS_ERROR){
                result.setText("request params error");
            }
        } catch (RemoteException e) {
            e.printStackTrace();
        }
    }
}

运行结果

image1.png

image2.png

项目地址

https://github.com/peace710/aidl

Addition

https://github.com/peace710/AgeraCore

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,558评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,002评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,036评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,024评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,144评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,255评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,295评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,068评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,478评论 1 305
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,789评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,965评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,649评论 4 336
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,267评论 3 318
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,982评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,223评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,800评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,847评论 2 351

推荐阅读更多精彩内容

  • 概述 AIDL是一个缩写,全称是Android Interface Definition Language,也就是...
    _执_念__阅读 3,031评论 0 10
  • 一、概述 AIDL 意思即 Android Interface Definition Language,翻译过来就...
    业志陈阅读 117,987评论 45 174
  • Android Aidl 的使用 Binder框架 -- android AIDL 的使用 Binder框架 – ...
    赤兔欢阅读 2,174评论 7 5
  • 十八岁考上大学,义无反顾踏上锈迹斑斑的列车去往千里之外的他乡,而后工作,结婚,生子,并没有动过回家的念头,但是今年...
    蒋澄非阅读 335评论 0 2
  • 把这两个勾上,选择主线程和隐藏系统函数调用,然后揪出耗时的函数 单元测试 多文件上传EECF3FF1-A7E9-4...
    Mg明明就是你阅读 321评论 0 2