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的方法

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

②输入名称后,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文件

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

④打开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的代理,具体如下)
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张图片


你可能感兴趣的:(Android,战争之小白成神)