AIDL整理
aidl 整理
AIDL(Android Interface Definition Language)是一种用于定义 Android 应用程序中进程间通信(IPC)的接口的语言。AIDL 允许 Android 应用程序中的不同进程之间进行通信,例如 Activity、Service 和 BroadcastReceiver 等组件。
下面是一些使用 AIDL 的步骤:
-
定义 AIDL 接口:在 Android 项目中创建一个 AIDL 文件,该文件定义了您要使用的方法和参数。AIDL 文件应该放在
src/main/aidl
目录下。例如,如果您要定义一个名为IMyService
的接口,则应创建一个名为IMyService.aidl
的文件。 -
实现 AIDL 接口:在服务端创建一个 Java 类,并实现您定义的 AIDL 接口。该类应该继承
android.os.Binder
类。您的实现应该在onBind()
方法中返回一个IBinder
对象,该对象用于在客户端和服务端之间进行通信。 -
在客户端中绑定服务:在客户端应用程序中使用
bindService()
方法来绑定服务。这将使您可以通过返回的IBinder
对象调用服务端实现的 AIDL 接口中的方法。 -
调用 AIDL 方法:在客户端中,您可以使用服务端返回的
IBinder
对象来获取 AIDL 接口,并使用该接口调用服务端实现的方法。
AIDL 是一种强类型的接口定义语言,可以通过它定义 Java 类型之间的通信。AIDL 可以定义基本数据类型、数组、列表、映射、Parcelable 对象等等。通过使用 AIDL,您可以使您的应用程序中的不同组件之间进行高效、可靠的通信。
客户端具体实现
在 Android 应用程序中,客户端是指需要访问远程服务的组件。例如,Activity 可以是一个客户端,它可以通过绑定服务来访问服务中的方法。
下面是一个简单的客户端实现步骤:
-
定义 AIDL 接口:客户端和服务端必须共享同一个 AIDL 接口定义。因此,您需要将服务端定义的 AIDL 文件复制到客户端项目的
src/main/aidl
目录下。 -
绑定服务:您可以使用
bindService()
方法来绑定服务。该方法需要一个 Intent 参数,用于指定要绑定的服务。例如,如果您要绑定一个名为MyService
的服务,则可以使用以下代码:
Intent intent = new Intent(this, MyService.class);
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
其中,mConnection
是一个 ServiceConnection
对象,用于处理客户端和服务端之间的连接状态。
- 实现 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) {
// 断开连接
}
};
- 调用服务端方法:在
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 接口。要实现服务端进程,您需要执行以下步骤:
- 定义 AIDL 接口
在服务端进程中,您需要定义客户端与服务端之间要使用的 AIDL 接口。您可以使用 aidl
工具自动生成 AIDL 接口代码。具体而言,您需要在服务端进程中创建一个 .aidl
文件,并在其中定义客户端和服务端之间的方法。例如:
interface IMyAidlInterface {
int add(int a, int b);
}
这个示例中,我们定义了一个名为 IMyAidlInterface
的 AIDL 接口,其中包含一个名为 add()
的方法,用于计算两个整数的和。
- 实现 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()
方法。
- 在服务中启动服务
在服务端进程中,您需要创建一个服务,并在服务中实现 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 接口与服务通信。
- 在 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
,以允许客户端连接到该服务。
- 处理客户端请求
在服务端进程中,您需要处理客户端发送的 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
:将服务标记为重要服务。这使得系统会更努力地保持服务在运行状态,以避免其被杀死。