Binder Java层实现(二):AIDL使用以及原理分析

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.运行查看结果

·自己实现Binder


上面我们展示了如何使用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驱动类,写的过程中我们细细来分析各个函数的功能。

5.自己实现Binder驱动IPC通信


定义公共接口

从上面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();

  • 5
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值