Android进程间通信(二):AIDL
来源:互联网 发布:mysql必知必会 pdf 编辑:程序博客网 时间:2024/05/17 04:33
AIDL (Android Interface Definition Language)即Android接口定义语言。若需多线程同时处理其他应用进程的请求才有必要使用AIDL。如果不需多线程交互,则可使用Messenger(请看《Android进程间通信(一):Messenger》);而如果不需跨进程通信,使用Binder即可。
AIDL接口通常与Service联合使用。客户端通过bindService()与服务器建立连接。每当客户端调用服务器的AIDL接口时,系统就会从服务器进程的线程池中派发一个新线程进行处理,因此AIDL接口的实现必须做到线程安全。注意检查客户端传过来的参数是否合法。服务器端抛出的异常不会发回给客户端。
一、定义AIDL接口
1、创建.aidl文件
在Android Studio中创建.aidl文件:点击Android Studio最左侧的Project竖选项卡,然后在其展栏的左上角点选Project,接着在app/src/main/aidl/目录(若aidl目录不存在则新建)上右键,New > AIDL > AIDL File,在最后打开的对话框输入.aidl文件名并按Finish按钮即可。.aidl文件路径示例:app/src/main/aidl/*com/company/app*/IRemoteService.aidl。创建或修改好文件后,点击Android Studio顶部工具栏的Tools > Android > Sync Project with Gradle Files,就会在app/build/generated/source/aidl/debug/目录下生成或更新*com/company/app*/IRemoteService.java文件。
如果客户端与服务器处在不同的应用中,那么客户端也需要拷贝一份.aidl文件以便生成相应的.java文件。
.aidl文件中只能定义一个接口及其若干个方法。
AIDL默认支持的数据类型:
Java语言的基本类型,如int、long、char、boolean、String、CharSequence等等;
还有List 、Map。
List、Map的元素数据类型为上述列表中的类型,或者其他AIDL生成的接口,或者可打包(parcelable)类型。List可以当泛型类使用(例如List),而Map则不支持。
其他类型需要import(具体请看下文的第二节:在进程间传递对象)。
所有非基本类型在作为参数时需要有一个方向标签(in、out、inout)来表明数据的流向。跨进程传递参数的过程包括数据序列化、传输、接收和反序列化等。方向标签有助于系统优化数据传输过程,提高效率。
———— in ———— 》远程客户端 本地服务器 《———— out ———— // inout是最耗费资源的:系统需要先把客户端的实参对象序列化,// 传到服务器,然后反序列化成形参对象供服务器使用。// 接口方法调用完返回时,系统又需要把服务器的形参对象序列化,// 传到客户端,再反序列化后修改客户端的实参对象。// 若是在同一个进程中,修改形参对象就能直接影响实参对象,// 就像C/C++中的指针那样。void charsToUpper(inout char[] lowerChars);
AIDL有一个关键字oneway,远程客户端调用其修饰的方法时,不阻塞等待结果而是立即返回;本地调用则是同步等待(如同未修饰一样)。它所修饰的方法返回值必须是void,否则生成的.java文件会报错。
// IRemoteService.aidlpackage com.company.app;// 这个oneway修饰接口中所有方法oneway interface IRemoteService{ // 这个oneway只修饰此方法 oneway void doSomething();}
2、实现接口
自动生成的IRemoteService.java文件有一个抽象子类:Stub,它继承了Binder类并实现了.aidl文件中的接口。
private final IRemoteService.Stub mBinder = new IRemoteService.Stub() { public void doSomething() { // Do something here }};
3、暴露接口给客户端
// 服务器的Service类public class RemoteService extends Service { // 当客户端调用bindService()时,系统调用此方法。 // 客户端调用的详情请看下文的第三节:跨进程调用一个方法。 @Override public IBinder onBind(Intent intent) { // Return the interface return mBinder; } private final IRemoteService.Stub mBinder = new IRemoteService.Stub() { public void doSomething() { // Do something here } }; ...}
二、在进程间传递对象
如果需要跨进程传递一个对象,那么它的类必须做到以下几点,使得Android在跨进程传递数据时可以分解(decompose)、重组(marshalled)它:
1、实现Parcelable接口;
2、实现writeToParcel()方法,它负责把类的状态保存到Parcel中;
3、在类内创建一个名为CREATOR的静态成员,它是一个实现Parcelable.Creator接口的对象;
4、创建一个.aidl文件来声明这个可打包(parcelable)的类。
以下为Android的Rect类示例:
// Rect.aidlpackage android.graphics;// 定义Rect类,以便AIDL能找到它并知道它实现了可打包协议。parcelable Rect;
此时.java文件需要自己实现:
// Rect.javapackage android.graphics;import android.os.Parcel;import android.os.Parcelable;public final class Rect implements Parcelable { public int left; public int top; public int right; public int bottom; public static final Parcelable.Creator<Rect> CREATOR = newParcelable.Creator<Rect>() { public Rect createFromParcel(Parcel in) { return new Rect(in); } public Rect[] newArray(int size) { return new Rect[size]; } }; public Rect() { } private Rect(Parcel in) { readFromParcel(in); } @Override public void writeToParcel(Parcel out, int flags) { out.writeInt(left); out.writeInt(top); out.writeInt(right); out.writeInt(bottom); } public void readFromParcel(Parcel in) { left = in.readInt(); top = in.readInt(); right = in.readInt(); bottom = in.readInt(); } @Override public int describeContents() { return 0; } ...}
然后就可以在.aidl文件中使用这个类:
```// IAnotherRemoteService.aidlpackage com.company.app;import android.graphics.Rect;interface IAnotherRemoteService{ void setRect(in Rect rect);}
三、跨进程调用一个方法
1、包含.aidl文件到上述路径(请看上文第一节《定义AIDL接口》的第1小节《创建.aidl文件》);
2、定义一个IBinder接口的实例;
3、实现ServiceConnection;
4、调用Context.bindService(),传递参数ServiceConnection;
5、在ServiceConnection.onServiceConnected()的实现中,会有一个IBinder接口参数名为service,调用YourInterfaceName.Stub.asInterface((IBinder)service)来把它转换成之前定义的AIDL接口类型。
6、调用在AIDL接口中声明的方法。需要注意连接出错时抛出的DeadObjectException,它是调用远程方法时可能出现的唯一异常。
7、调用Context.unbindService()来断开连接。
对象作为跨进程方法参数时,其引用计数会增加。匿名对象可以作为参数。
package com.company.app;import android.app.Activity;import android.os.Bundle;import android.content.Intent;import android.content.ServiceConnection;import android.content.ComponentName;import android.os.IBinder;import android.util.Log;// 客户端的Activitypublic class ClientActivity extends Activity { private final String LOG_TAG = "ClientActivity"; private IRemoteService mIRemoteService; private boolean mIsBound; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_client); } @Override protected void onStart() { super.onStart(); Intent intent = new Intent(this, IRemoteService.class); // 调用此方法与服务器连接 bindService(intent, mServiceConnection, BIND_AUTO_CREATE); } @Override protected void onStop() { super.onStop(); unbindService(mServiceConnection); mIsBound = false; } private ServiceConnection mServiceConnection = new ServiceConnection() { public void onServiceConnected(ComponentName className, IBinder service) { // asInterface()是在Stub中自动生成的helper方法 mIRemoteService = IRemoteService.Stub.asInterface(service); mIsBound = true; } public void onServiceDisconnected(ComponentName className) { Log.e(LOG_TAG, "Service has unexpectedly disconnected"); mIRemoteService = null; mIsBound = false; } }; // 在适当的时机调用远程服务器接口。 // 注意应当避免在Activity主线程中调用。 // mIRemoteService.doSomething(); ...}
参考资料:
Android > Develop > API Guides > Android Interface Definition Language (AIDL)
https://developer.android.com/intl/zh-cn/guide/components/aidl.html#PassingObjects
- Android进程间通信(二):AIDL
- Android 进程间通信AIDL讲解 二
- Android进程间通信(二):使用AIDL实现进程间通信
- Android之AIDL(进程间通信)
- Android之AIDL(进程间通信)
- Android 进程间通信(AIDL)
- Android AIDL进程间通信(IPC)
- Android 进程间通信(AIDL)
- android AIDL 进程间通信
- android aidl进程间通信
- Android 进程间通信AIDL
- Android进程间通信--AIDL
- Android进程间通信--AIDL
- android 进程间通信(aidl)
- android AIDL进程间通信
- android进程间通信:AIDL
- Android AIDL 进程间通信
- Android进程间通信AIDL
- QT图片透明的设置
- The server does not support version 3.0 of the J2EE Web module specification
- 关于跳槽的11条建议
- 线段树
- 将短链接转化成正常链接
- Android进程间通信(二):AIDL
- 自定义地图数据瓦片化请求的一种实现方案
- Cocoa 鼠标事件
- 条件随机场
- FLAG_ACTIVITY_NEW_TASK
- CentOS启动和停止服务详解
- 工作第三日
- ZZULIOJ 1791 旋转矩阵
- 利用JOSN和Jquery写省市级联