Android 中的 Android 接口定义语言 (AIDL) 是什么?
Android 接口定义语言 (AIDL) 类似于您可能使用过的其他 IDL。它允许您定义客户端和维修商都同意的编程接口,以便使用进程间通信 (IPC) 相互交谈。传统上,Android 方式一个进程无法访问其他进程的内存。因此,为了能够进行通信,他们将对象分解为操作系统可以很好理解的原语,并为您跨边界编组对象。尝试进行编组的代码写下来很乏味,因此 Android 使用 AIDL 为您处理它。
Note: Using AIDL is important as long as you permit clients from different applications to access your service for IPC and need to handle multithreading in your service.
但是在开始设计自己的 AIDL 之前,请注意对 AIDL 的调用是直接正确的函数调用!因此,您不应该在执行决策期间假设线程。取决于决定是来自本地进程内的线程还是来自外部进程,发生的情况会有所不同。
具体来说
- 由本地进程组成的调用在做出决定的同一线程中执行。如果此调用通常来自您的主 UI 线程,那么它将继续在 AIDL 接口中执行,但是如果它是另一个(线程),那么该调用将在服务中执行您的!
- 来自外部进程的调用是从平台在您自己的进程中维护的线程池中分派的。您希望为来自未知线程的传入呼叫做好准备,同时在同一时间发生多个呼叫。
- oneway关键字决定了远程调用的行为,使用时,外部调用不会阻塞;它只是发送交易数据并立即返回。接口的实现最终从 Binder 线程池中接收这个作为日常调用,作为传统的远程调用。如果单程与区域呼叫一起使用,则不会产生影响,因此呼叫保持同步。
定义 AIDL 接口
您必须使用Java编程语言语法在.aidl文件中定义 AIDL 接口,然后将其保留在托管服务的设备和绑定到该服务的其他应用程序的 ASCII 文本文件(在 src/ 目录中)中。要创建.aidl文件,请使用此链接!
Sounds confusing?
好吧,这里有一个例子:
进程 A 需要呼叫状态信息来确定它是否必须更改呼叫类型(例如将语音更改为视频)。您将从某些听众那里获得呼叫状态,但要将呼叫类型从音频更改为视频,进程 A 需要一个挂钩来改变。这种“挂钩”或调整呼叫的方式通常是“> 电话类”的一部分,该类是电话流程的一部分。为了从 Telephony 进程中获取这样一条信息,可以编写一个电话服务(它作为 android 电话进程的邻域运行),它可以让您质疑或更改呼叫类型。由于这里的进程 A(客户端)正在使用与电话进程通信以更改呼叫类型的远程服务,因此它必须具有与服务对话的接口。由于电话服务是提供者,而流程 A(客户端)是用户,所以他们都必须就他们将理解和坚持的接口(协议)达成一致。这样的接口就是 AIDL,它允许您(通过外部服务)与 Telephony 进程对话并完成一些工作。
简单地说,AIDL 是客户获得的“协议”,它告诉客户请求服务的方式。服务本身将具有该协议的副本(因为它已为其客户发布)。然后,服务将实施有关在邀请到达后如何处理的详细信息,或者说何时有人在讲课
因此,处理 A 请求通过服务更改呼叫,服务获取请求,它与电话进程对话(因为它是其中的一部分)并将呼叫更改为视频。
需要注意的重要一点是,AIDL 仅仅是多线程环境所必需的。如果您不影响多线程拱门,您将取消 Binder。示例:进程 A 需要呼叫状态信息来确定是否必须更改呼叫类型(例如音频到视频呼叫,反之亦然)。您将从某些听众那里获得呼叫状态,但要将呼叫类型从音频更改为视频,进程 A 需要一个挂钩来改变。这种“挂钩”或调整呼叫的方式通常是“> 电话类”的一部分,该类是电话流程的一部分。为了从 Telephony 进程中获取此类信息,可以编写一个电话服务(它作为 android 电话进程的邻域运行),它可以让您质疑或更改呼叫类型。由于这里的进程 A(客户端)正在使用与电话进程通信以更改呼叫类型的远程服务,因此它必须具有与服务对话的接口。由于电话服务是提供者,而流程 A(客户端)是用户,所以他们都必须就他们将理解和坚持的接口(协议)达成一致。这样的接口就是 AIDL,它允许您(通过外部服务)与 Telephony 进程对话并完成一些工作。
简单地说,AIDL 是客户获得的“协议”,它告诉客户请求服务的方式。服务本身将具有该协议的副本(因为它已为其客户发布)。然后,服务将实施有关在邀请到达后如何处理的详细信息,或者说何时有人在讲课
因此,处理 A 请求通过服务更改呼叫,服务获取请求,它与电话进程对话(因为它是其中的一部分)并将呼叫更改为视频。
需要注意的重要一点是,AIDL 仅仅是多线程环境所必需的。如果您不影响多线程拱门,您将取消 Binder。
以下是指导您操作的代码片段:
Java
// Declare any non-default types
// here with import statements
interface GeeksforGeeks {
int add(int x,int y);
int sub(int x,int y);
}
Java
public class AidlServiceGfG extends Service {
private static final String TAG = "AIDLServiceLogs";
private static final String className = " AidlService";
public AidlService() {
Log.i(TAG, className+" Constructor");
}
@Override
public IBinder onBind(Intent intent) {
// GfG Example of Binder
Log.i(TAG, className+" onBind");
return iCalculator.asBinder();
}
@Override
public void onCreate() {
super.onCreate();
Log.i(TAG, className+" onCreate");
}
@Override
public void onDestroy() {
super.onDestroy();
Log.i(TAG, className+" onDestroy");
}
ICalculator.Stub iCalculator = new ICalculator.Stub() {
@Override
public int add(int x, int y) throws RemoteException {
Log.i(TAG, className+" add Thread Name: "+Thread.currentThread().getName());
int z = x+y;
return z;
}
@Override
public int sub(int x, int y) throws RemoteException {
Log.i(TAG, className+" add Thread Name: "+Thread.currentThread().getName());
int z = x-y;
return z;
}
};
}
Java
// Returns the stub
ServiceConnection serviceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
Log.i(TAG, className + " onServiceConnected");
iCalculator = ICalculator.Stub.asInterface(service);
}
@Override
public void onServiceDisconnected(ComponentName name) {
unbindService(serviceConnection);
}
};
上述代码的 AIDL 服务是:
Java
public class AidlServiceGfG extends Service {
private static final String TAG = "AIDLServiceLogs";
private static final String className = " AidlService";
public AidlService() {
Log.i(TAG, className+" Constructor");
}
@Override
public IBinder onBind(Intent intent) {
// GfG Example of Binder
Log.i(TAG, className+" onBind");
return iCalculator.asBinder();
}
@Override
public void onCreate() {
super.onCreate();
Log.i(TAG, className+" onCreate");
}
@Override
public void onDestroy() {
super.onDestroy();
Log.i(TAG, className+" onDestroy");
}
ICalculator.Stub iCalculator = new ICalculator.Stub() {
@Override
public int add(int x, int y) throws RemoteException {
Log.i(TAG, className+" add Thread Name: "+Thread.currentThread().getName());
int z = x+y;
return z;
}
@Override
public int sub(int x, int y) throws RemoteException {
Log.i(TAG, className+" add Thread Name: "+Thread.currentThread().getName());
int z = x-y;
return z;
}
};
}
这是服务连接:
Java
// Returns the stub
ServiceConnection serviceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
Log.i(TAG, className + " onServiceConnected");
iCalculator = ICalculator.Stub.asInterface(service);
}
@Override
public void onServiceDisconnected(ComponentName name) {
unbindService(serviceConnection);
}
};
结论
AIDL 使用 binder 内核驱动程序来形成调用。一旦你进行调用,一个方式标识符和每个对象都被打包到一个缓冲区中并复制到一个外部进程,一个活页夹线程等待读取信息。当在同一个进程中进行调用时,因此在同一个后端,不存在代理对象,那么调用是直接的,没有打包或解包。