Android跨进程通信之AIDL

目录
1. AIDL的概念
2. AIDL的基本使用方法
3. AIDL在Android5.0以后的更新使用


一、AIDL的概念

AIDL是Android Interface definition language(Android接口定义语言)的缩写,是Android中IPC(Inter-Process Communication)(进程间通信)方式中的一种。AIDL的作用是让你可以在自己的APP里绑定一个其他APP的service,这样你的APP可以和其他APP交互。(为方便理解,本文将两个APP分为Server端和Client端,CLient访问Server的service)

二、AIDL的基本使用方法

1.编写Server端的AIDL文件

① AIDL的基本语法和JAVA类似,定义AIDL文件类似于定义JAVA中的接口。接口中的方法即Client可以访问Server的方法

Android跨进程通信之AIDL_第1张图片

②输入名称后,studio帮我们建立AIDL文件

// IMyAidlInterface.aidlpackage com.example.demonacoding.aidlservice02;// Declare any non-default types here with import statementsinterface IMyAidlInterface {    /**     * Demonstrates some basic types that you can use as parameters     * and return values in AIDL.     */   String getName();   int getAge();}

其中String getName()int getAge()为Client访问的方法

sync project一下工程,可以在发现studio已经帮我们建立相应的java文件

Android跨进程通信之AIDL_第2张图片

④打开java文件可以看到如下代码

package com.example.*******.aidlservice02;// Declare any non-default types here with import statementspublic interface IMyAidlInterface extends android.os.IInterface{public static abstract class Stub extends android.os.Binder implements IMyAidlInterface{private static final java.lang.String DESCRIPTOR = "com.example.*******.aidlservice02.IMyAidlInterface";/** Construct the stub at attach it to the interface. */public Stub(){this.attachInterface(this, DESCRIPTOR);}/** * Cast an IBinder object into an com.example.demonacoding.aidlservice02.IMyAidlInterface interface, * generating a proxy if needed. */public static com.example.demonacoding.aidlservice02.IMyAidlInterface asInterface(android.os.IBinder obj){if ((obj==null)) {return null;}android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);if (((iin!=null)&&(iin instanceof com.example.demonacoding.aidlservice02.IMyAidlInterface))) {return ((com.example.demonacoding.aidlservice02.IMyAidlInterface)iin);}return new com.example.demonacoding.aidlservice02.IMyAidlInterface.Stub.Proxy(obj);}@Override public android.os.IBinder asBinder(){return this;}@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_getName:{data.enforceInterface(DESCRIPTOR);java.lang.String _result = this.getName();reply.writeNoException();reply.writeString(_result);return true;}case TRANSACTION_getAge:{data.enforceInterface(DESCRIPTOR);int _result = this.getAge();reply.writeNoException();reply.writeInt(_result);return true;}}return super.onTransact(code, data, reply, flags);}private static class Proxy implements com.example.demonacoding.aidlservice02.IMyAidlInterface{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;}/**     * Demonstrates some basic types that you can use as parameters     * and return values in AIDL.     */@Override public java.lang.String getName() throws android.os.RemoteException{android.os.Parcel _data = android.os.Parcel.obtain();android.os.Parcel _reply = android.os.Parcel.obtain();java.lang.String _result;try {_data.writeInterfaceToken(DESCRIPTOR);mRemote.transact(Stub.TRANSACTION_getName, _data, _reply, 0);_reply.readException();_result = _reply.readString();}finally {_reply.recycle();_data.recycle();}return _result;}@Override public int getAge() throws android.os.RemoteException{android.os.Parcel _data = android.os.Parcel.obtain();android.os.Parcel _reply = android.os.Parcel.obtain();int _result;try {_data.writeInterfaceToken(DESCRIPTOR);mRemote.transact(Stub.TRANSACTION_getAge, _data, _reply, 0);_reply.readException();_result = _reply.readInt();}finally {_reply.recycle();_data.recycle();}return _result;}}static final int TRANSACTION_getName = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);static final int TRANSACTION_getAge = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);}/**     * Demonstrates some basic types that you can use as parameters     * and return values in AIDL.     */public java.lang.String getName() throws android.os.RemoteException;public int getAge() throws android.os.RemoteException;}

比较重要的是Stub抽象类,该类继承于Binder类。如果要实现接口的具体方法,只需要在Server端新建service,然后新建内部类继承Stub,作为onBind()方法的返回类,内部类中即为接口方法的具体实现。

为什么我们主要使用的是Stub抽象类,但AIDL生成的Java文件却把Stub作为一个接口的内部类?

这是因为Stub既需要继承android.os.IInterface类,又需要继承android.os.Binder类,但Java中不允许多继承,只能用一个接口实现android.os.IInterface,然后在内部新建一个类实现该接口,变相实现“多继承”。

Stub类中还有很多方法,包括asInerface(),onTransact()以及内部类Proxy,这些对AIDL原理的理解很有帮助,这里就不为大家一一解释了,有兴趣的同学可以自行百度,或者推荐大家阅读Android中的AIDL原理

⑤在Server端建立service,在其内部新建内部类继承Stub类作为onBind()的返回值,内部类中实现具体的接口方法(这是service的基本使用方法,就不赘述了)

⑥接下来就是Client端的实现。首先需要将Server端中的AIDL文件(包括包名,即连同文件夹)全部复制到Client中,然后同样sync project工程,得到和Server端一样的AIDL java文件

⑦接着和一般启动service一样,调用bindService(*,*,*)启动Server端的service即可访问另一个APP中的方法~(注意在public void onServiceConnected()中,需要调用asInterface()返回IBinder的代理,具体如下)
Android跨进程通信之AIDL_第3张图片


三、AIDL在Android5.0以后的更新使用

Android5.0之后不能用隐式Intent启动bindService(),所以需要另外写一个方法来将隐式intent变成显式intent,方法如下:

public static Intent createExplicitFromImplicitIntent(Context context, Intent implicitIntent) {//Retrieve all services that can match the given intent        PackageManager pm = context.getPackageManager();        List resolveInfo = pm.queryIntentServices(implicitIntent, 0);//Make sure only one match was found        if (resolveInfo == null || resolveInfo.size() != 1) {            return null;        }//Get component info and create ComponentName        ResolveInfo serviceInfo = resolveInfo.get(0);        String packageName = serviceInfo.serviceInfo.packageName;        String className = serviceInfo.serviceInfo.name;        ComponentName component = new ComponentName(packageName, className);//Create a new intent. Use the old one for extras and such reuse        Intent explicitIntent = new Intent(implicitIntent);//Set the component to be explicit        explicitIntent.setComponent(component);        return explicitIntent;    }

方法实现:利用PackageManager检索是否匹配隐式intent的action,如果有的话获取该action对应service包名,类名,然后附加到client的隐式intent上,使之变为显示intent就可以启动了。具体使用:
Android跨进程通信之AIDL_第4张图片


更多相关文章

  1. Android中设置动画循环旋转的方法
  2. 向模拟器发短信打电话的方法
  3. android手机屏幕适配方法
  4. Android基础知识之Manifest文件的组织结构
  5. android中一些配置文件的参数的意义
  6. Android实现文件上传功能
  7. android Gradle打包修改生成的apk文件名称
  8. Android中遍历文件夹、比较文件类型测试
  9. 更新android studio gradle 不成功解决方法

随机推荐

  1. PHP使用swoole实现多线程爬虫
  2. 怎么将网站的php版本信息隐藏起来
  3. php实现性能优化
  4. 关于php中变量的初始化以及赋值方式的介
  5. 通过header函数设置响应头解决php跨域问
  6. PHP安装BCMath扩展
  7. 浅析PHP类的自动加载和命名空间
  8. 关于在php中使用curl发送get请求时参数传
  9. 基于AIML的PHP聊天机器人
  10. PHP多任务秒级定时器的实现方法