目录
1. AIDL的概念
2. AIDL的基本使用方法
3. AIDL在Android5.0以后的更新使用
AIDL是Android Interface definition language(Android接口定义语言)的缩写,是Android中IPC(Inter-Process Communication)(进程间通信)方式中的一种。AIDL的作用是让你可以在自己的APP里绑定一个其他APP的service,这样你的APP可以和其他APP交互。(为方便理解,本文将两个APP分为Server端和Client端,CLient访问Server的service)
① AIDL的基本语法和JAVA类似,定义AIDL文件类似于定义JAVA中的接口。接口中的方法即Client可以访问Server的方法
②输入名称后,studio帮我们建立AIDL文件
// IMyAidlInterface.aidl
package com.example.demonacoding.aidlservice02;
// Declare any non-default types here with import statements
interface 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 statements
public 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的代理,具体如下)
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就可以启动了。具体使用: