AIDL整理

发布时间 2023-03-27 15:45:45作者: 懒懒初阳

aidl 整理

AIDL(Android Interface Definition Language)是一种用于定义 Android 应用程序中进程间通信(IPC)的接口的语言。AIDL 允许 Android 应用程序中的不同进程之间进行通信,例如 Activity、Service 和 BroadcastReceiver 等组件。

下面是一些使用 AIDL 的步骤:

  1. 定义 AIDL 接口:在 Android 项目中创建一个 AIDL 文件,该文件定义了您要使用的方法和参数。AIDL 文件应该放在 src/main/aidl 目录下。例如,如果您要定义一个名为 IMyService 的接口,则应创建一个名为 IMyService.aidl 的文件。

  2. 实现 AIDL 接口:在服务端创建一个 Java 类,并实现您定义的 AIDL 接口。该类应该继承 android.os.Binder 类。您的实现应该在 onBind() 方法中返回一个 IBinder 对象,该对象用于在客户端和服务端之间进行通信。

  3. 在客户端中绑定服务:在客户端应用程序中使用 bindService() 方法来绑定服务。这将使您可以通过返回的 IBinder 对象调用服务端实现的 AIDL 接口中的方法。

  4. 调用 AIDL 方法:在客户端中,您可以使用服务端返回的 IBinder 对象来获取 AIDL 接口,并使用该接口调用服务端实现的方法。

AIDL 是一种强类型的接口定义语言,可以通过它定义 Java 类型之间的通信。AIDL 可以定义基本数据类型、数组、列表、映射、Parcelable 对象等等。通过使用 AIDL,您可以使您的应用程序中的不同组件之间进行高效、可靠的通信。

客户端具体实现

在 Android 应用程序中,客户端是指需要访问远程服务的组件。例如,Activity 可以是一个客户端,它可以通过绑定服务来访问服务中的方法。

下面是一个简单的客户端实现步骤:

  1. 定义 AIDL 接口:客户端和服务端必须共享同一个 AIDL 接口定义。因此,您需要将服务端定义的 AIDL 文件复制到客户端项目的 src/main/aidl 目录下。

  2. 绑定服务:您可以使用 bindService() 方法来绑定服务。该方法需要一个 Intent 参数,用于指定要绑定的服务。例如,如果您要绑定一个名为 MyService 的服务,则可以使用以下代码:

Intent intent = new Intent(this, MyService.class);
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);

其中,mConnection 是一个 ServiceConnection 对象,用于处理客户端和服务端之间的连接状态。

  1. 实现 ServiceConnection 接口:您需要实现 ServiceConnection 接口中的两个方法 onServiceConnected()onServiceDisconnected(),以处理客户端和服务端之间的连接状态。例如:

java

private ServiceConnection mConnection = new ServiceConnection() {
    @Override
    public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
        // 获取服务端实现的 AIDL 接口
        IMyService myService = IMyService.Stub.asInterface(iBinder);
        
        // 调用服务端方法
        try {
            myService.doSomething();
        } catch (RemoteException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void onServiceDisconnected(ComponentName componentName) {
        // 断开连接
    }
};
  1. 调用服务端方法:在 onServiceConnected() 方法中,您可以获取服务端实现的 AIDL 接口,并使用该接口调用服务端实现的方法。例如,如果服务端实现了一个名为 doSomething() 的方法,则可以使用以下代码来调用该方法:
try {
    myService.doSomething();
} catch (RemoteException e) {
    e.printStackTrace();
}

在这个例子中,myService 是服务端实现的 AIDL 接口。使用 try-catch 块捕获可能的远程异常。

Android 11之后做了服务调用限制,需要在client中加对应query声明才能绑定服务

Aidl 通讯客户端进程。如何绑定服务

要与 AIDL 服务通信,客户端必须通过绑定服务来与服务进行连接。绑定服务使用 bindService() 方法,其签名如下:

java

public boolean bindService(Intent service, ServiceConnection conn, int flags)

其中,service 参数是一个 Intent 对象,用于指定要绑定的服务;conn 参数是一个 ServiceConnection 对象,用于处理客户端和服务端之间的连接状态;flags 参数是一个标志位,用于指定服务绑定的行为。

下面是一个简单的客户端代码示例,用于绑定到一个 AIDL 服务:

private IMyAidlInterface mService;

private ServiceConnection mConnection = new ServiceConnection() {
    @Override
    public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
        // 当服务连接成功时调用,获取服务端实现的 AIDL 接口
        mService = IMyAidlInterface.Stub.asInterface(iBinder);
    }

    @Override
    public void onServiceDisconnected(ComponentName componentName) {
        // 当服务连接意外断开时调用
        mService = null;
    }
};

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    // 创建 Intent 对象,用于指定要绑定的服务
    Intent intent = new Intent();
    intent.setComponent(new ComponentName("com.example.myapplication", "com.example.myapplication.MyService"));

    // 绑定服务
    boolean result = bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
    if (result) {
        Log.d(TAG, "Service bound successfully.");
    } else {
        Log.d(TAG, "Failed to bind service.");
    }
}

@Override
protected void onDestroy() {
    super.onDestroy();

    // 断开服务连接
    if (mService != null) {
        unbindService(mConnection);
        mService = null;
    }
}

在这个示例中,IMyAidlInterface 是您在服务端定义的 AIDL 接口。在 onServiceConnected() 方法中,您可以获取服务端实现的 AIDL 接口,以便在客户端中调用服务端方法。在 onServiceDisconnected() 方法中,您应该清除对服务端 AIDL 接口的引用。

onCreate() 方法中,您需要创建一个 Intent 对象,用于指定要绑定的服务。在这个例子中,ComponentName 的第一个参数是服务所在的包名,第二个参数是服务类的完整类名。

最后,在 onDestroy() 方法中,您需要断开服务连接。如果您没有正确地释放服务端 AIDL 接口的引用,可能会导致内存泄漏等问题。

aidl服务端

在 AIDL 通信中,服务端进程必须实现客户端与服务端之间定义的 AIDL 接口。要实现服务端进程,您需要执行以下步骤:

  1. 定义 AIDL 接口

在服务端进程中,您需要定义客户端与服务端之间要使用的 AIDL 接口。您可以使用 aidl 工具自动生成 AIDL 接口代码。具体而言,您需要在服务端进程中创建一个 .aidl 文件,并在其中定义客户端和服务端之间的方法。例如:

interface IMyAidlInterface {
    int add(int a, int b);
}

这个示例中,我们定义了一个名为 IMyAidlInterface 的 AIDL 接口,其中包含一个名为 add() 的方法,用于计算两个整数的和。

  1. 实现 AIDL 接口

在服务端进程中,您需要实现定义的 AIDL 接口。这意味着您需要创建一个 Java 类,并在其中实现接口中定义的所有方法。您可以使用 Android 提供的 Binder 类来实现 AIDL 接口。例如:

public class MyAidlInterfaceImpl extends IMyAidlInterface.Stub {
    @Override
    public int add(int a, int b) {
        return a + b;
    }
}

在这个示例中,我们创建了一个名为 MyAidlInterfaceImpl 的 Java 类,该类继承了 IMyAidlInterface.Stub 类,这个类实现了 IMyAidlInterface 中定义的 add() 方法。

  1. 在服务中启动服务

在服务端进程中,您需要创建一个服务,并在服务中实现 AIDL 接口。要启动服务,您可以使用以下代码:

public class MyService extends Service {
    private MyAidlInterfaceImpl mBinder;

    @Override
    public void onCreate() {
        super.onCreate();
        mBinder = new MyAidlInterfaceImpl();
    }

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

在这个示例中,我们创建了一个名为 MyService 的服务。在服务的 onCreate() 方法中,我们创建了一个 MyAidlInterfaceImpl 对象,并将其存储在 mBinder 成员变量中。在服务的 onBind() 方法中,我们返回 mBinder 对象的 IBinder 接口,以便客户端可以使用 AIDL 接口与服务通信。

  1. 在 AndroidManifest.xml 文件中注册服务

在服务端进程中,您需要在 AndroidManifest.xml 文件中注册服务。例如:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.myapplication">

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">

        <service
            android:name=".MyService"
            android:exported="true" />

    </application>

</manifest>

在这个示例中,我们将 MyService 服务注册到AndroidManifest.xml 文件中,并将 exported 属性设置为 true,以允许客户端连接到该服务。

  1. 处理客户端请求

在服务端进程中,您需要处理客户端发送的 AIDL 接口请求。当客户端调用 AIDL 接口中定义的方法时,这些请求将发送到服务端进程,并且服务端进程应该能够处理这些请求并返回响应。要处理这些请求,您可以使用 onTransact() 方法。例如:

java

public class MyAidlInterfaceImpl extends IMyAidlInterface.Stub {
    @Override
    public int add(int a, int b) throws RemoteException {
        return a + b;
    }

    @Override
    public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
        switch (code) {
            case TRANSACTION_add:
                int arg1 = data.readInt();
                int arg2 = data.readInt();
                int result = add(arg1, arg2);
                reply.writeInt(result);
                return true;
            default:
                return super.onTransact(code, data, reply, flags);
        }
    }
}

在这个示例中,我们使用 onTransact() 方法来处理客户端发送的 add() 方法调用。在 onTransact() 方法中,我们首先使用 switch 语句检查请求的代码。如果请求的代码是 TRANSACTION_add,则我们读取两个整数参数,并使用 add() 方法计算它们的和。然后,我们将计算结果写入回复 reply 参数,并返回 true 表示请求已成功处理。如果请求的代码不是 TRANSACTION_add,则我们调用 super.onTransact() 方法以处理其他请求。

这就是服务端进程实现 AIDL 接口的基本步骤。通过这些步骤,您可以创建一个服务端进程,以允许客户端使用 AIDL 接口与您的应用程序进行通信。

Bindservice 方法整理

bindService() 方法用于在客户端与服务之间建立连接。该方法需要传入一个 Intent 对象,该对象指定了要连接的服务。此外,您还需要提供一个 ServiceConnection 对象,以处理服务的连接和断开连接事件。

下面是 bindService() 方法的基本用法:

Intent intent = new Intent(context, MyService.class);
bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE);

在这个示例中,我们首先创建了一个 Intent 对象,该对象指定了要连接的服务(在这里是 MyService)。然后,我们调用 bindService() 方法,并传入 Intent 对象、ServiceConnection 对象和一个标志 Context.BIND_AUTO_CREATE。该标志指示系统在客户端不存在时自动创建服务。

下面是 bindService() 方法的参数解释:

  • intent:指定要连接的服务的 Intent 对象。该对象通常包含服务的完整类名,以及其他信息(例如服务的包名、操作等)。

  • connection:指定要处理服务连接和断开连接事件的 ServiceConnection 对象。该对象包含两个回调方法:onServiceConnected()onServiceDisconnected()

  • flags:指定服务绑定的标志。可以指定多个标志,这些标志是通过按位或运算符 | 连接的。常用的标志包括:

bindService() 方法中,flags 参数用于指定如何绑定服务。它可以接受多个标志,每个标志都控制不同的行为。以下是常用的标志及其用途:

  • Context.BIND_AUTO_CREATE:如果服务还没有运行,则创建服务。这将导致调用服务的 onCreate() 方法。
  • Context.BIND_DEBUG_UNBIND:在服务解除绑定时生成调试日志消息。
  • Context.BIND_NOT_FOREGROUND:不将服务绑定到前台,即使它是前台服务。
  • Context.BIND_ABOVE_CLIENT:使服务在客户端之上运行。这使得客户端无法通过 stopService() 停止服务。
  • Context.BIND_ALLOW_OOM_MANAGEMENT:允许服务被杀死以进行内存管理。
  • Context.BIND_WAIVE_PRIORITY:降低客户端与服务通信的优先级,以提高系统响应性。
  • Context.BIND_IMPORTANT:将服务标记为重要服务。这使得系统会更努力地保持服务在运行状态,以避免其被杀死。