Android Interface Definition Language (AIDL)
The Android Interface Definition Language (AIDL) is similar to other IDLs you might have worked with. It allows you to define the programming interface that both the client and service agree upon in order to communicate with each other using interprocess communication (IPC).
翻译:AIDL 和其他IDL一样。通过接口来沟通(IPC)
On Android, one process cannot normally access the memory of another process. So to talk, they need to decompose their objects into primitives that the operating system can understand, and marshall the objects across that boundary for you. The code to do that marshalling is tedious to write, so Android handles it for you with AIDL.
翻译:在android系统中,一个进程不能access另外一个进程的memory.所以要打散再组合。如果手写这个过程很麻烦,所以Android提供了AIDL机制
Note: Using AIDL is necessary only if you allow clients from different applications to access your service for IPC and want to handle multithreading in your service. If you do not need to perform concurrent IPC across different applications, you should create your interface by implementing a Binder or, if you want to perform IPC, but do not need to handle multithreading, implement your interface using a Messenger. Regardless, be sure that you understand Bound Services before implementing an AIDL.
翻译:在用AIDL之前先理解Bound Service
Before you begin designing your AIDL interface, be aware that calls to an AIDL interface are direct function calls. You should not make assumptions about the thread in which the call occurs. What happens is different depending on whether the call is from a thread in the local process or a remote process. Specifically:
翻译:注意,这些都是方法调用,你不需要假定这些方法occur的线程。根据调用来自本地还是远程,情况会有所不同。
- Calls made from the local process are executed in the same thread that is making the call. If this is your main UI thread, that thread continues to execute in the AIDL interface. If it is another thread, that is the one that executes your code in the service. Thus, if only local threads are accessing the service, you can completely control which threads are executing in it (but if that is the case, then you shouldn't be using AIDL at all, but should instead create the interface by implementing a Binder).
如果是本地process调用的话,情况会比较简单
- Calls from a remote process are dispatched from a thread pool the platform maintains inside of your own process. You must be prepared for incoming calls from unknown threads, with multiple calls happening at the same time. In other words, an implementation of an AIDL interface must be completely thread-safe. Calls made from one thread on same remote object arrive in order on the receiver end.
翻译:注意多线程
- The
oneway
keyword modifies the behavior of remote calls. When used, a remote call does not block; it simply sends the transaction data and immediately returns. The implementation of the interface eventually receives this as a regular call from theBinder
thread pool as a normal remote call. Ifoneway
is used with a local call, there is no impact and the call is still synchronous.
翻译:oneway
定义 AIDL 接口
You must define your AIDL interface in an .aidl
file using the Java programming language syntax, then save it in the source code (in the src/
directory) of both the application hosting the service and any other application that binds to the service.
翻译:两边都要有aidl接口
When you build each application that contains the .aidl
file, the Android SDK tools generate an IBinder
interface based on the .aidl
file and save it in the project's gen/
directory. The service must implement the IBinder
interface as appropriate. The client applications can then bind to the service and call methods from the IBinder
to perform IPC.
翻译:要实现自动生成的IBinder接口
To create a bounded service using AIDL, follow these steps:
- Create the .aidl file
This file defines the programming interface with method signatures
翻译:创建.aidl文件
The Android SDK tools generate an interface in the Java programming language, based on your .aidl
file. This interface has an inner abstract class named Stub
that extends Binder
and implements methods from your AIDL interface. You must extend the Stub
class and implement the methods.
翻译:继承Stub类,实现stub类里面的方法
3. Expose the interface to clients
Implement a Service
and override onBind()
to return your implementation of the Stub
class.
翻译:实现Service ,overide onBind方法来返回你Stub类的实现。
Caution: Any changes that you make to your AIDL interface after your first release must remain backward compatible in order to avoid breaking other applications that use your service. That is, because your .aidl
file must be copied to other applications in order for them to access your service's interface, you must maintain support for the original interface.
翻译:注意向后兼容
1. Create the .aidl file
AIDL uses a simple syntax that lets you declare an interface with one or more methods that can take parameters and return values. The parameters and return values can be of any type, even other AIDL-generated interfaces.
You must construct the .aidl
file using the Java programming language. Each .aidl
file must define a single interface and requires only the interface declaration and method signatures.
By default, AIDL supports the following data types:
- All primitive types in the Java programming language (such as
int
,long
,char
,boolean
, and so on) String
CharSequence
List
- All elements in the
List
must be one of the supported data types in this list or one of the other AIDL-generated interfaces or parcelables you've declared. AList
may optionally be used as a "generic" class (for example,List<String>
). The actual concrete class that the other side receives is always anArrayList
, although the method is generated to use theList
interface. - 翻译:只支持ArrayList
- All elements in the
Map
must be one of the supported data types in this list or one of the other AIDL-generated interfaces or parcelables you've declared. Generic maps, (such as those of the formMap<String,Integer>
) are not supported. The actual concrete class that the other side receives is always aHashMap
, although the method is generated to use theMap
interface. - 翻译:只支持HashMap
You must include an import
statement for each additional type not listed above, even if they are defined in the same package as your interface.
翻译:如果不是上面列举的类型的话,要import之
When defining your service interface, be aware that:
- Methods can take zero or more parameters, and return a value or void.
- All non-primitive parameters require a directional tag indicating which way the data goes. Either
in
,out
, orinout
(see the example below).Primitives are
in
by default, and cannot be otherwise. -
Caution: You should limit the direction to what is truly needed, because marshalling parameters is expensive.
- All code comments included in the
.aidl
file are included in the generatedIBinder
interface (except for comments before the import and package statements). - String and int constants can be defined in the AIDL interface. For example:
const int VERSION = 1;
. - Method calls are dispatched by a transact() code, which normally is based on a method index in the interface. Because this makes versioning difficult, you could manually assign the transaction code to a method:
void method() = 10;
- Annotate nullable arguments or return types using
@nullable
. - Here is an example
.aidl
file:
// IRemoteService.aidl
package com.example.android
// Declare any non-default types here with import statements
/** Example service interface */
internal interface IRemoteService {
/** Request the process ID of this service, to do evil things with it. */
val pid:Int
/** Demonstrates some basic types that you can use as parameters
* and return values in AIDL.
*/
fun basicTypes(anInt:Int, aLong:Long, aBoolean:Boolean, aFloat:Float,
aDouble:Double, aString:String)
}
Simply save your .aidl
file in your project's src/
directory and when you build your application, the SDK tools generate the IBinder
interface file in your project's gen/
directory. The generated file name matches the .aidl
file name, but with a .java
extension (for example, IRemoteService.aidl
results in IRemoteService.java
).
If you use Android Studio, the incremental build generates the binder class almost immediately. If you do not use Android Studio, then the Gradle tool generates the binder class next time you build your application—you should build your project with gradle assembleDebug
(or gradle assembleRelease
) as soon as you're finished writing the .aidl
file, so that your code can link against the generated class.
2. Implement the interface
When you build your application, the Android SDK tools generate a .java
interface file named after your .aidl
file. The generated interface includes a subclass named Stub
that is an abstract implementation of its parent interface (for example, YourInterface.Stub
) and declares all the methods from the .aidl
file.
Note: Stub
also defines a few helper methods, most notably asInterface()
, which takes an IBinder
(usually the one passed to a client's onServiceConnected()
callback method) and returns an instance of the stub interface. See the section Calling an IPC Method for more details on how to make this cast.
To implement the interface generated from the .aidl
, extend the generated Binder
interface (for example, YourInterface.Stub
) and implement the methods inherited from the .aidl
file.
Here is an example implementation of an interface called IRemoteService
(defined by the IRemoteService.aidl
example, above) using an anonymous instance:
private final IRemoteService.Stub binder = new IRemoteService.Stub() {
public int getPid(){
return Process.myPid();
}
public void basicTypes(int anInt, long aLong, boolean aBoolean,
float aFloat, double aDouble, String aString) {
// Does nothing
}
};
Now the binder
is an instance of the Stub
class (a Binder
), which defines the RPC interface for the service. In the next step, this instance is exposed to clients so they can interact with the service.
There are a few rules you should be aware of when implementing your AIDL interface:
- Incoming calls are not guaranteed to be executed on the main thread, so you need to think about multithreading from the start and properly build your service to be thread-safe.
- 翻译:注意线程安全
- By default, RPC calls are synchronous. If you know that the service takes more than a few milliseconds to complete a request, you should not call it from the activity's main thread, because it might hang the application (Android might display an "Application is Not Responding" dialog)—you should usually call them from a separate thread in the client.
- 翻译:注意不要阻塞主线程
- No exceptions that you throw are sent back to the caller.
- 翻译:异常不会sent back给caller
3. Expose the interface to clients
Once you've implemented the interface for your service, you need to expose it to clients so they can bind to it. To expose the interface for your service, extend Service
and implement onBind()
to return an instance of your class that implements the generated Stub
(as discussed in the previous section). Here's an example service that exposes the IRemoteService
example interface to clients.
public class RemoteService extends Service {
@Override
public void onCreate() {
super.onCreate();
}
@Override
public IBinder onBind(Intent intent) {
// Return the interface
return binder;
}
private final IRemoteService.Stub binder = new IRemoteService.Stub() {
public int getPid(){
return Process.myPid();
}
public void basicTypes(int anInt, long aLong, boolean aBoolean,
float aFloat, double aDouble, String aString) {
// Does nothing
}
};
}
Now, when a client (such as an activity) calls bindService()
to connect to this service, the client's onServiceConnected()
callback receives the binder
instance returned by the service's onBind()
method.
The client must also have access to the interface class, so if the client and service are in separate applications, then the client's application must have a copy of the .aidl
file in its src/
directory (which generates the android.os.Binder
interface—providing the client access to the AIDL methods).
When the client receives the IBinder
in the onServiceConnected()
callback, it must callYourServiceInterface.Stub.asInterface(service)
to cast the returned parameter to YourServiceInterface
type. For example:
翻译:注意调用YourServiceInterface.Stub.asInterface(service)
方法来强转
IRemoteService iRemoteService;
private ServiceConnection mConnection = new ServiceConnection() {
// Called when the connection with the service is established
public void onServiceConnected(ComponentName className, IBinder service) {
// Following the example above for an AIDL interface,
// this gets an instance of the IRemoteInterface, which we can use to call on the service
iRemoteService = IRemoteService.Stub.asInterface(service);
}
// Called when the connection with the service disconnects unexpectedly
public void onServiceDisconnected(ComponentName className) {
Log.e(TAG, "Service has unexpectedly disconnected");
iRemoteService = null;
}
};
参考:For more sample code, see the RemoteService.java
class in ApiDemos.