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

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

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Java工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
img
img
img
img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新

如果你觉得这些内容对你有帮助,可以添加V获取:vip1024b (备注Java)
img

最后

分享一些系统的面试题,大家可以拿去刷一刷,准备面试涨薪。

这些面试题相对应的技术点:

  • JVM
  • MySQL
  • Mybatis
  • MongoDB
  • Redis
  • Spring
  • Spring boot
  • Spring cloud
  • Kafka
  • RabbitMQ
  • Nginx

大类就是:

  • Java基础
  • 数据结构与算法
  • 并发编程
  • 数据库
  • 设计模式
  • 微服务
  • 消息中间件

程序员,每个月给你发多少工资,你才会想老板想的事?

程序员,每个月给你发多少工资,你才会想老板想的事?

程序员,每个月给你发多少工资,你才会想老板想的事?

程序员,每个月给你发多少工资,你才会想老板想的事?

程序员,每个月给你发多少工资,你才会想老板想的事?

程序员,每个月给你发多少工资,你才会想老板想的事?

程序员,每个月给你发多少工资,你才会想老板想的事?

程序员,每个月给你发多少工资,你才会想老板想的事?

程序员,每个月给你发多少工资,你才会想老板想的事?

一个人可以走的很快,但一群人才能走的更远。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
img

注Java)**
[外链图片转存中…(img-SoD4emug-1712782634634)]

最后

分享一些系统的面试题,大家可以拿去刷一刷,准备面试涨薪。

这些面试题相对应的技术点:

  • JVM
  • MySQL
  • Mybatis
  • MongoDB
  • Redis
  • Spring
  • Spring boot
  • Spring cloud
  • Kafka
  • RabbitMQ
  • Nginx

大类就是:

  • Java基础
  • 数据结构与算法
  • 并发编程
  • 数据库
  • 设计模式
  • 微服务
  • 消息中间件

[外链图片转存中…(img-DMiwE3np-1712782634635)]

[外链图片转存中…(img-2sArOGeR-1712782634635)]

[外链图片转存中…(img-nGNTgamu-1712782634635)]

[外链图片转存中…(img-tB6esuYk-1712782634636)]

[外链图片转存中…(img-rlX8w9EP-1712782634636)]

[外链图片转存中…(img-jYFHPy0J-1712782634636)]

[外链图片转存中…(img-uqJzD9yJ-1712782634636)]

[外链图片转存中…(img-2JJbbEPr-1712782634637)]

[外链图片转存中…(img-BoRsmmbN-1712782634637)]

一个人可以走的很快,但一群人才能走的更远。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
[外链图片转存中…(img-2kl8sRtl-1712782634637)]

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值