Data
需实现Parcelable
接口。
以下是android studio的默认实现。
/**
-
Created by lion on 2016/10/11.
-
要通过Bundle传递的数据需要实现Parcelable接口,
-
一旦你实现了这个接口android studio会提示你帮
-
你快速实现带有Parcel的构造函数。
*/
public class Data implements Parcelable {
…
protected Data(Parcel in) {
…
}
public static final Creator CREATOR = new Creator() {
@Override
public Data createFromParcel(Parcel in) {
return new Data(in);
}
@Override
public Data[] newArray(int size) {
return new Data[size];
}
};
}
c. 编译aidl文件
到这里aidl的编写就完成了,我们build下工程,编译器会自动生成IDataManager.java文件。
该文件在工程的~/app/build/generated/source/aidl/debug/<package>/IDataManager.java
,这里我们先不讲解生成的这个类,先看下如何使用aidl。
d. 添加Service类(远端服务)
添加一个Service
命名为DataManagerService
我们在DataManagerService
中实现一个静态的IDataManager.Stub
的类
private static final IDataManager.Stub mBinder = new IDataManager.Stub() {
@Override
public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException {
}
@Override
public int getDataTypeCount() throws RemoteException {
// todo return some data
return 0;
}
@Override
public List getData() throws RemoteException {
// todo return some data
return null;
}
@Override
public String getUrlContent(String url) throws RemoteException {
// todo return some data
return null;
}
};
在onBind
方法中返回这个Binder,这样当我们调用Activity的bindService
方法的时候就能返回这个binder对象了。
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
e.绑定服务并测试夸进程通信
在你需要调用的Activity中添加如下代码:
/**
- data manager service 的远程引用
*/
private IDataManager dataManagerService = null;
/**
- 创建Service Connection用于监听service链接与断开链接
*/
private ServiceConnection dataServiceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
dataManagerService = IDataManager.Stub.asInterface(service);
}
@Override
public void onServiceDisconnected(ComponentName name) {
dataManagerService = null;
}
};
当你的Activity启动时绑定远程服务
@Override
protected void onCreate(Bundle savedInstanceState) {
…
bindService(new Intent(this, DataManagerService.class), dataServiceConnection,
Context.BIND_AUTO_CREATE);
}
接下来我们编写测试代码,在button的回调函数中我们编写如下测试代码:
public void callService(View view) {
try {
System.out.println(dataManagerService.getDataTypeCount());
StringBuilder sb = new StringBuilder();
for (Data data : dataManagerService.getData()) {
System.out.println(data.toString());
sb.append(data.toString()).append(“\n”);
}
textData.setText(sb.toString());
new Thread(new Runnable() {
@Override
public void run() {
try {
System.out.println(dataManagerService.getUrlContent(“http://www.baidu.com”));
} catch (RemoteException e) {
e.printStackTrace();
}
}
}).start();
} catch (RemoteException e) {
e.printStackTrace();
}
}
f.运行查看结果
上面我们展示了如何使用AIDL文件实现进程间通信,为了能够更好的理解进程间通信机制接下来将会展示如何手动编写一个Binder实现IPC。
aidl生成类分析
将Android Studio切换到项目视图,找到如下文件:
我们将这个接口文件简化以下,看看系统多给我们做了些什么。
public interface IDataManager extends android.os.IInterface {
/**
- Local-side IPC implementation stub class.
*/
public static abstract class Stub extends android.os.Binder implements org.github.lion.aidl_demo.IDataManager {
private static class Proxy implements org.github.lion.aidl_demo.IDataManager {}
}
}
IDataManager
这个是我们定义的aidl接口,这个接口里面就要定义我们需要的要成服务能力的接口;
IDataManager.Stub
这个是一个继承自Binder并且实现了IDataManager的抽象类;
IDataManager.Stub.Proxy
这个是一个私有内部类,实现了IDataManager;
我们知道Binder是Android中的IPC通信驱动,从类结构我们就可以看出最终的实际功能类是IDataManager.Stub.Proxy
。具体的类方法我们暂时不做分析,接下来我们不使用aidl文件自己实现一个Binder驱动类,写的过程中我们细细来分析各个函数的功能。
定义公共接口
从上面aidl生成的类我们看出需要实现IPC通信需要实现IInterface接口,并且继承Binder类从中间驱动。所以首先我们先定义公共接口继承IInterface接口。
//IDataManager.java
public interface IDataManager2 extends IInterface {
// 返回值为基本数据类型,定义接口时不需要做特殊处理
int getDataCount() throws RemoteException;
// 自定义的返回数据类型需要实现Parcelable接口,进程间通信不能直接共享内存,需要将对象持久化。
// 所以自定义的类需要实现Parcelable接口
List getData() throws RemoteException;
}
/**
-
Data2.java
-
Created by lion on 2016/10/11.
-
要通过Bundle传递的数据需要实现Parcelable接口,
-
一旦你实现了这个接口android studio会提示你帮
-
你快速实现带有Parcel的构造函数。
*/
public class Data2 implements Parcelable {
private int id;
private String content;
public Data2() {
}
protected Data2(Parcel in) {
id = in.readInt();
content = in.readString();
}
public static final Creator CREATOR = new Creator() {
@Override
public Data2 createFromParcel(Parcel in) {
return new Data2(in);
}
@Override
public Data2[] newArray(int size) {
return new Data2[size];
}
};
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(id);
dest.writeString(content);
}
@Override
public String toString() {
return "id = " + id + " content = " + content;
}
}
继承Binder并实现IDataManager2接口的类作为Binder的本体。
为了让代码逻辑更加清晰,这回我们的Binder类不再写成内部类。
public abstract class DataManagerNative extends Binder implements IDataManager2 {
// Binder描述符,唯一标识符
private static final String DESCRIPTOR = “com.github.onlynight.aidl_demo2.aidl.IDataManager2”;
// 每个方法对应的ID
private static final int TRANSACTION_getDataCount = IBinder.FIRST_CALL_TRANSACTION;
private static final int TRANSACTION_getData = IBinder.FIRST_CALL_TRANSACTION + 1;
public DataManagerNative() {
attachInterface(this, DESCRIPTOR);
}
/**
-
将Binder转化为IInterface接口
-
@param binder
-
@return
*/
public static IDataManager2 asInterface(IBinder binder) {
if (binder == null) {
return null;
}
//同一进程内直接返回
IInterface iin = binder.queryLocalInterface(DESCRIPTOR);
if ((iin != null) && (iin instanceof IDataManager2)) {
return (IDataManager2) iin;
}
//不在同一进程使用代理获取远程服务
return new Proxy(binder);
}
@Override
public IBinder asBinder() {
return this;
}
/**
-
我们查看Binder的源码就可以看出实际上transact方法真正的执行体
-
是这个onTransact方法。
-
@param code 服务器回掉的方法ID,每一个方法都有一个唯一id,
-
这样方法回调时可通过id判断回调的方法。
-
@param data 输入的参数,传递给服务端的参数
-
@param reply 输出的参数,服务器返回的数据
-
@param flags 默认传入0
-
@return
-
@throws RemoteException 远端服务器无响应抛出该错误。
*/
@Override
protected boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
switch (code) {
case TRANSACTION_getDataCount: {
data.enforceInterface(DESCRIPTOR);
int _result = this.getDataCount();
reply.writeNoException();
reply.writeInt(_result);
return true;
}
case TRANSACTION_getData: {
data.enforceInterface(DESCRIPTOR);
List _result = this.getData();
reply.writeNoException();
reply.writeTypedList(_result);
return true;
}
}
return super.onTransact(code, data, reply, flags);
}
/**
- 代理类,调用transact方法。
*/
private static class Proxy implements IDataManager2 {
private IBinder remote;
Proxy(IBinder remote) {
this.remote = remote;
}
public String getInterfaceDescriptor() {
return DESCRIPTOR;
}
@Override
public int getDataCount() throws RemoteException {
// 输入参数
Parcel _data = Parcel.obtain();
//输出参数
Parcel _reply = Parcel.obtain();
int _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
remote.transact(TRANSACTION_getDataCount, _data, _reply, 0);
_reply.readException();
_result = _reply.readInt();
} finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
@Override
public List getData() throws RemoteException {
Parcel _data = Parcel.obtain();
Parcel _reply = Parcel.obtain();
List _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
remote.transact(TRANSACTION_getData, _data, _reply, 0);
_reply.readException();
_result = _reply.createTypedArrayList(Data2.CREATOR);
} finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
@Override
public IBinder asBinder() {
return remote;
}
}
}
DataManagerNative.DESCRIPTER
Binder描述符,唯一标识符,服务端和客户端都可以通过该ID定位到Binder实例。
DataManagerNative.TRANSACTION_XXX
自定义的IInterface方法的唯一标识符。
DataManagerNative.asInterface
将Binder转换为IInterface就可以直接调用我们自己定义的方法啦。
DataManagerNative.onTransact
根据不同的TRANSACTION_ID
调用调用不同的方法。
DataManagerNative.Proxy
代理远端Binder,对外提供IDataManager2
的功能。
DataManagerNative.Proxy.transact
想调用远端Binder的transact方法。
可以看到DataManagerNative
是个抽象类,并没有实现IDataManager2
中的方法。所以我们需要在实例化这个类的时候实现这些方法,这些操作都放到Service中去完成。
Service中Binder的实现我们和上一次使用同样的代码。
public class DataManagerService extends Service {
private static List data = new ArrayList<>();
static {
Data2 data1 = new Data2();
data1.setId(1);
data1.setContent(“data1”);
data.add(data1);
Data2 data2 = new Data2();
data2.setId(2);
data2.setContent(“data2”);
data.add(data2);
Data2 data3 = new Data2();
data3.setId(3);
data3.setContent(“data3”);
data.add(data3);
Data2 data4 = new Data2();
data4.setId(4);
data4.setContent(“data4”);
data.add(data4);
Data2 data5 = new Data2();
data5.setId(5);
data5.setContent(“data5”);
data.add(data5);
}
// 可以看到我们在这里实现了这个Binder,这里才是这个Binder的本体。
private static DataManagerNative binder = new DataManagerNative() {
@Override
public int getDataCount() throws RemoteException {
return data.size();