Android跨进程通信之AIDL
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的方法
②输入名称后,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文件
④打开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的代理,具体如下)
三、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中设置动画循环旋转的方法
- 向模拟器发短信打电话的方法
- android手机屏幕适配方法
- Android基础知识之Manifest文件的组织结构
- android中一些配置文件的参数的意义
- Android实现文件上传功能
- android Gradle打包修改生成的apk文件名称
- Android中遍历文件夹、比较文件类型测试
- 更新android studio gradle 不成功解决方法