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

*/

void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,double aDouble, String aString);

int getDataTypeCount();

List getData();

String getUrlContent(String url);

}

List<Data> getData()这个方法中使用了自定义的数据类型,虽然我们在文件开头写了import但是还是无法通过编译,我们需要在sdk的platform下修改framework.aidl,完整路径如下:~/platforms/android-xx/framework.aidl,加入我们自己添加的类名即可:

// user define aidl parcelable data

parcelable org.github.lion.aidl_demo.Data;

这个路径实际上是系统定义的Parcelable类~/platforms/android-xx/framework.aidl,这里我们不建议修改这个文件,另一种方式是aidl文件,定义如下:

// Data.aidl Data 类的完整包名为 org.github.lion.aidl_demo.Data,我们定义的aidl文件如下即可。

package org.github.lion.aidl_demo;

parcelable Data;

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 {

最后

针对最近很多人都在面试,我这边也整理了相当多的面试专题资料,也有其他大厂的面经。希望可以帮助到大家。

下面的面试题答案都整理成文档笔记。也还整理了一些面试资料&最新2021收集的一些大厂的面试真题(都整理成文档,小部分截图)

在这里插入图片描述

最新整理电子书

在这里插入图片描述

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 {

最后

针对最近很多人都在面试,我这边也整理了相当多的面试专题资料,也有其他大厂的面经。希望可以帮助到大家。

下面的面试题答案都整理成文档笔记。也还整理了一些面试资料&最新2021收集的一些大厂的面试真题(都整理成文档,小部分截图)

[外链图片转存中…(img-j4vjCtb9-1714118303518)]

最新整理电子书

[外链图片转存中…(img-NOSHgxER-1714118303519)]

本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

  • 4
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值