Andorid总结 - AIDL
2016-05-08 20:27
441 查看
使用AIDL的必要条件是你允许来自不同应用的client来访问你的service做IPC的操作,并且需要处理多线程的情况。
如果你不要做跨进程的IPC,那么你应该使用“Extending the Binder class”方法,参考Andorid总结 - Bound Services
如果需要跨进程IPC但是不会有多线程的操作,那么你应该使用“Using a Messenger”方法,参考Andorid总结 - Bound Services
在使用AIDL时,client与service在同一进程和不在同一进程的区别:
在相同进程中,service中的AIDL方法会在调用者所在的线程中执行。
在不同进程中,远程进程的调用会从维护在本进程中的一个线程池中随机分配一个线程来执行。AIDL的接口实现必须是线程安全的。
oneway 关键字用来修饰远程调用的行为。如果使用的话,呢么远程调用就不会被block了;它之后发送数据并立马返回。 oneway对本地调用不起作用,调用依旧是同步的。
在应用程序编译之后,Android SDK tools 会根据”.aidl”生成一个IBinder的接口,这个接口保存在build目录下。service必须实现IBinder,然后把这个IBinder传给client调用。
具体步骤如下:
创建.aidl文件
“.aidl”文件中定义一个接口,接口里的方法提供给client调用。
AIDL使用很简单的Java语法,里面什么的方法可以带有参数和返回值。参数和返回值的类型可以为任意的类型,甚至可以用AIDL生成的接口做参数。只能定义方法,不能有变量。
AIDL中可以用的默认类型有:
String
CharSequence
List
Map
使用额外的数据类型时,必须使用import来导入,即使在同一个包中。
编译完成后的目录看似这样:
2.实现接口
如上图,当编译完成后,Android SDK tools会给我们在generated/source中生成对应的java接口文件。生成的接口包含了一个叫“Stub”的子类,比如“YourServiceInterface.Stub”,这个子类同事也继承了Binder,而我们的Servcie就是要实现这个Stub子类,作为Binder来传递给client使用。
在实现AIDL接口时,有几个小规格要注意:
调用接口不保证在主线程执行,所以需要考虑启动时的多线程和建立时的线程安全。
默认,RPC调用是同步的。所以如果请求比较耗时的话,请使用子线程来调用。
client端不用收到任务异常消息。
把接口暴露给clients
只需在onBinder()函数中把上一步的实现了Stub的对象mBinder 返回给clients。
而client的onServiceConnected() callback 就会接受到这个mBinder 对象。接收到之后通过调用 YourServiceInterface.Stub.asInterface(service) 把mBinder转换为 YourServiceInterface类型. For example:
如果你不要做跨进程的IPC,那么你应该使用“Extending the Binder class”方法,参考Andorid总结 - Bound Services
如果需要跨进程IPC但是不会有多线程的操作,那么你应该使用“Using a Messenger”方法,参考Andorid总结 - Bound Services
在使用AIDL时,client与service在同一进程和不在同一进程的区别:
在相同进程中,service中的AIDL方法会在调用者所在的线程中执行。
在不同进程中,远程进程的调用会从维护在本进程中的一个线程池中随机分配一个线程来执行。AIDL的接口实现必须是线程安全的。
oneway 关键字用来修饰远程调用的行为。如果使用的话,呢么远程调用就不会被block了;它之后发送数据并立马返回。 oneway对本地调用不起作用,调用依旧是同步的。
定义AIDL接口
你必须要定义AIDL接口在 “.aidl”文件中,语法跟Java类似。“.aidl”可以通过Android Studio来帮助创建,Android Studio会默认创建一个文件夹来保存.aidl的文件。在应用程序编译之后,Android SDK tools 会根据”.aidl”生成一个IBinder的接口,这个接口保存在build目录下。service必须实现IBinder,然后把这个IBinder传给client调用。
具体步骤如下:
创建.aidl文件
“.aidl”文件中定义一个接口,接口里的方法提供给client调用。
AIDL使用很简单的Java语法,里面什么的方法可以带有参数和返回值。参数和返回值的类型可以为任意的类型,甚至可以用AIDL生成的接口做参数。只能定义方法,不能有变量。
AIDL中可以用的默认类型有:
String
CharSequence
List
Map
使用额外的数据类型时,必须使用import来导入,即使在同一个包中。
// 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); }
编译完成后的目录看似这样:
2.实现接口
如上图,当编译完成后,Android SDK tools会给我们在generated/source中生成对应的java接口文件。生成的接口包含了一个叫“Stub”的子类,比如“YourServiceInterface.Stub”,这个子类同事也继承了Binder,而我们的Servcie就是要实现这个Stub子类,作为Binder来传递给client使用。
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 } };
在实现AIDL接口时,有几个小规格要注意:
调用接口不保证在主线程执行,所以需要考虑启动时的多线程和建立时的线程安全。
默认,RPC调用是同步的。所以如果请求比较耗时的话,请使用子线程来调用。
client端不用收到任务异常消息。
把接口暴露给clients
只需在onBinder()函数中把上一步的实现了Stub的对象mBinder 返回给clients。
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 } };
}
而client的onServiceConnected() callback 就会接受到这个mBinder 对象。接收到之后通过调用 YourServiceInterface.Stub.asInterface(service) 把mBinder转换为 YourServiceInterface类型. For example:
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; } };
调用 IPC 方法
跟Bound Sercie类似,唯一需要注意的就是调用方法的时候,需要补货一个 异常 DeadObjectException。当连接断开的时候会抛出这个异常。在IPC中传递对象
可以在IPC中传递对象,但是这个对象必须实现Parcelable 接口。快速实现Parcelable 可以通过Android Studio的插件“android-parcelable-intellij-plugin”相关文章推荐
- 使用C++实现JNI接口需要注意的事项
- Android IPC进程间通讯机制
- Android Manifest 用法
- [转载]Activity中ConfigChanges属性的用法
- Android之获取手机上的图片和视频缩略图thumbnails
- Android之使用Http协议实现文件上传功能
- Android学习笔记(二九):嵌入浏览器
- android string.xml文件中的整型和string型代替
- i-jetty环境搭配与编译
- android之定时器AlarmManager
- android wifi 无线调试
- Android Native 绘图方法
- Android java 与 javascript互访(相互调用)的方法例子
- android 代码实现控件之间的间距
- android FragmentPagerAdapter的“标准”配置
- Android"解决"onTouch和onClick的冲突问题
- android:installLocation简析
- android searchView的关闭事件
- SourceProvider.getJniDirectories