由于本人英文能力实在有限,不足之初敬请谅解
本博客只要没有注明“转”,那么均为原创,转贴请注明本博客链接链接
Android Interface Definition Language (AIDL)
android接口定义语言
AIDL (Android Interface Definition Language) 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). 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.
AIDL与其他IDL语言类似,你需要做一些工作。
它允许你定义客户端与服务端达成一致的程序接口使用进程间通信相互交流。
在ANdroid上面,一个进程不能正常的访问另一个进程的内存。
所以说,他们需要分解他们的对象为操作系统可以理解的基本单位,然后为你把这些对象按次序跨越进程边界
书写这些代码是单调冗长的,所以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只有在你允许来自不同应用的客户端跨进程通信访问你的service,并且想要在你的service种处理多线程的时候才是必要的。
如果你不需要执行不同应用之间的IPC并发,你应该通过实现Binder建立你的接口,或者如果你想执行IPC,但是不需要处理多线程。那么使用Messenger实现你的接口
不管怎样,确保你在实现一个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:
在你设计你的AIDL接口之前,请注意调用一个AIDL接口是直接的函数调用
你不应该假设线程在哪个调用中发生
情形与依赖调用是来自一个本地进程中的线程还是一个远程进程中的线程相关
尤其是:
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).
来自本地进程的调用与调用者在同一个线程中执行。
如果这是你的主UI线程,线程继续在AIDL接口中执行
如果是其他的线程,则它是一个在service中执行你的代码的线程
这样,如果只是本地线程访问这个service,你完全可以控制哪些线程在其中执行(但是如果是那样的话,那么你压根就不应该使用AIDL,而应该通过实现Binder建立接口)
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.
平台在你自己的进程中内部维护一个线程池中分配的远程进程的调用
你必须为从未知线程发出的即将到来的调用,并且是伴随同时多个调用做好准备
换句话说,AIDL接口的实现必须是完全的线程安全的
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 the Binder thread pool as a normal remote call.
If oneway is used with a local call, there is no impact and the call is still synchronous.
单向关键词限定了远程调用的行为
使用的时候,一个远程调用不会被阻塞;它只是简单的发送传输数据并且立即返回
最终接口的实现把它作为一个来自Binder线程池的常规调用、一个普通的远程调用来接收
如果本地调用使用单向的,那么就不会有影响,并且调用仍然是异步的
Defining an AIDL Interface
定义一个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文件中使用java编程语言语法定义你的AIDL接口,然后在提供service的应用中和任何绑定到这个service的应用中的源代码中(在src目录吓)保存它
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.
当你编译包含.aidl文件的应用时,Android SDK工具基于这个.aidl文件生成一个IBinder接口,并且把它保存到项目的gen目录吓
service必须恰当的实现这个IBinder接口
之后客户端应用可以绑定到这个服务上,然后从IBinder调用方法来执行IPC
To create a bounded service using AIDL, follow these steps:
使用AIDL建立一个邻接的service需要遵循下面的步骤
1.Create the .aidl file
This file defines the programming interface with method signatures.
1.建立.aidl文件
这个文件使用方法签名定义了语言接口
2.Implement the interface
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.
2.实现这个接口
Android SDk工具基于你的.aidl文件使用java语言生成一个接口
这个接口有一个内部抽象类,叫做Stub,它是继承Binder并且实现你AIDL接口的
你必须继承这个Stub类并且实现这些方法
3.Expose the interface to clients
Implement a Service and override onBind() to return your implementation of the Stub class.
3.暴露这个接口给客户端
实现一个service并且覆盖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.
警告:在你第一次发布AIDL之后的其中任何的改变必须保持向后兼容来避免破坏其他应用程序使用你的service
也就是说,因为你的.aidl文件必须被复制到其他应用程序中来让他们访问你service的接口,你必须维护原始接口的支持。
1. Create the .aidl file
1.建立.aidl文件
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.
AIDL使用一个简单的语法让你声明一个带有一个或者多个带有参数和返回值方法的接口
参数和返回值可以是任何类型,甚至是AIDL生成的接口
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.
你必须使用java语言构建.aidl文件
每一个.aidl文件必须定义一个简单的接口并且要求只有接口声明和方法签名
By default, AIDL supports the following data types:
默认的,AIDL支持下面数据类型:
All primitive types in the Java programming language (such as int, long, char, boolean, and so on)
String
CharSequence
List
java语言中的所有基本数据类型(比如int、long、char、boolean等等)
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.
A List may optionally be used as a "generic" class (for example, List<String>).
The actual concrete class that the other side receives is always an ArrayList, although the method is generated to use the List interface.
List中的所有元素必须是AIDL支持的类型之一,或者是一个其他AIDL生成的接口,或者是你定义的parcelable
List可以使用范型(例如,List<String>)
接收端的实际类经常是一个ArrayList,尽管方法是使用List接口生成的
Map
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 form Map<String,Integer> are not supported.
The actual concrete class that the other side receives is always a HashMap, although the method is generated to use the Map interface.
Map中的所有元素必须是AIDL支持的类型之一,或者是一个其他AIDL生成的接口,或者是你定义的parcelable
范型map是不被支持的(比如这种形式Map<String,Integer>)
接收端的实际类经常是一个HashMap,尽管方法是使用Map接口生成的
When defining your service interface, be aware that:
当定义你的service接口的时候,注意:
Methods can take zero or more parameters, and return a value or void.
方法可以接收0或多个参数,并且有返回值或者返回void
All non-primitive parameters require a directional tag indicating which way the data goes.
Either in, out, or inout (see the example below).
Primitives are in by default, and cannot be otherwise.
所有非基本数据类型要求要求一个定向的tag来指定数据是去往哪个方向的
无论是输入、输出,还是输入输出(参加下面的例子)
基本数据类型是默认支持的,并且不能是其他的。
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 generated IBinder interface (except for comments before the import and package statements).
.aidl文件中的所有的代码注释都在生成的IBinder接口中(除了在import和包声明之前的注释)
Only methods are supported; you cannot expose static fields in AIDL.
Here is an example .aidl file:
只支持方法,你不可以在AIDL暴露静态域
这有个.aidl文件的例子:
// IRemoteService.aidl package com.example.android; // Declare any non-default types here with import statements /** Example service interface */ interface IRemoteService { /** Request the process ID of this service, to do evil things with it. */ int getPid(); /** Demonstrates some basic types that you can use as parameters * and return values in AIDL. */ void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString); }
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).
简单的保存你的.aidl文件在你工程的src目录下,当你build你的应用时,SDK工具在你工程的gen目录下生成IBinder接口文件
生成的文件名字与.aidl名字匹配,但是是以.java为扩展名(例如IRemoteService.aidl对应为IRemoteService.java)
If you use Eclipse, the incremental build generates the binder class almost immediately.
If you do not use Eclipse, then the Ant tool generates the binder class next time you build your application—you should build your project with ant debug (or ant release) as soon as you're finished writing the .aidl file, so that your code can link against the generated class.
如果你使用Eclipse,增量编译几乎是立刻生成binder类。
如果你不使用Eclipse,那么Ant工具在你下次编译你的应用(你应该使用ant debug或者ant release编译你的工程)时生成binder类
一旦你写好了.aidl文件,你的代码就可以链接到生成的类上面了。
2. Implement the interface
2.实现接口
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.
当你编译你的应用时,Android SDK工具生成一个.java接口文件用你的.aidl文件命名
生成的接口包含一个名字为Stub的子类(比如YourInterface.Stub),这是一个它父类的抽象实现,并且声明了.aidl中所有的方法
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.
注意:Stub也定义了一些辅助的方法,最显著的就是asInterface(),它是用来接收一个IBinder(通常IBinder传递给客户端的onServiceConnected()回调方法)并且返回一个Stub接口的实例
更多细节参考Calling an IPC Method章节。
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.
为了实现来自.aidl文件生成的接口,需要继承Binder接口(例如YourInterface.Stub)并且实现从.aidl文件中继承的方法。
Here is an example implementation of an interface called IRemoteService (defined by the IRemoteService.aidl example, above) using an anonymous instance:
这有一个使用匿名实例实现一个叫IRemoteService(定义在IRemoteService.aidl中,例子如上)的接口的例子
private final IRemoteService.Stub mBinder = 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 mBinder 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.
mBinder是一个Stub类的实例
There are a few rules you should be aware of when implementing your AIDL interface:
当实现你的AIDL接口的时候有很多规则需要注意
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.
调用不保证在主线程中执行,所以你需要一开始就考虑多线程并且适当的build你的service为线程安全的
默认的,RPC调用是同步的。
如果你知道service需要花费一些时间来完成请求,你就不应该从activity的主线程中调用它,因为它可能使得应用没有响应(Android也许会显示一个ANR的对话框),通常你应该在客户端中一个单独的线程调用它
抛出的异常不会返回给调用者
3. Expose the interface to clients
3.暴露接口给客户端
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.
一旦你为service实现了接口,你需要把它暴露给客户端,这样他们才能绑定到上面
为了给你的service暴露接口,继承Service并且实现onBind()方法返回一个你实现生成的Stub类(像我们在上一结讨论的那样)
这有一个service暴露IRemoteService接口给客户端的例子
public class RemoteService extends Service { @Override public void onCreate() { super.onCreate(); } @Override public IBinder onBind(Intent intent) { // Return the interface return mBinder; } private final IRemoteService.Stub mBinder = 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 mBinder instance returned by the service's onBind() method.
现在,当一个客户端(比如一个activity)调用bindService()来连接到这个service,这个客户端的onServiceConnected()回调函数接收service中onBind()方法返回的mBinder实例
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).
客户端必须可以访问接口类,所以如果客户端和服务端在不同的应用中,那么客户端所在的应用必须有一份.aidl文件的副本在其src目录下(生成android.os.Binder接口,提供客户端访问AIDL方法都在这个目录下)
When the client receives the IBinder in the onServiceConnected() callback, it must call YourServiceInterface.Stub.asInterface(service) to cast the returned parameter to YourServiceInterface type.
For example:
当客户端在onServiceConnected()回调方法中接收到IBinder时,它必须调用你的ServiceInterface.Stub.asInterface(service)来把返回参数映射到你的ServiceInterface类型上。
例如:
IRemoteService mIRemoteService; 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 mIRemoteService = 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"); mIRemoteService = null; } };
For more sample code, see the RemoteService.java class in ApiDemos.
更多样本代码参见ApiDemos中的RemoteService.java
原文地址如下,英文水平实在有限,希望拍砖同时能给予指正。
http://developer.android.com/guide/components/aidl.html
转贴请保留以下链接
本人blog地址