欢迎光临
我们一直在努力

不用 AIDL,手把手教你手写 Binder 代理类

前言: 在日常 Android 开发中,我们习惯了用 AIDL 来定义跨进程接口。但 AIDL 本质上只是一个代码生成工具,它自动生成的 Stub 和 Proxy 类完全可以手写。理解手写 Binder 的过程,能帮助你深入掌握 Android IPC 机制的核心原理。


一、Binder 通信整体架构

在开始手写代码之前,我们先搞清楚 Binder 通信的核心角色。一次完整的跨进程调用,涉及四个关键组件:

客户端 App
  ↓ transact()
Proxy(代理类)
  ↓ Binder Driver
Stub(存根类)
  ↓ onTransact()
服务端实现

💡 核心原理: Proxy 负责把方法调用「打包」成 Parcel 数据,通过 Binder 驱动发送到服务端;Stub 负责「解包」Parcel,调用真正的业务实现,再把结果「打包」返回给客户端。


二、项目结构准备

本文的示例分为服务端和客户端两个模块。手写 Binder 不需要 AIDL 文件,但需要手动维护接口一致性。

📁 server (服务端)
📄 IMyManualService.java — 接口定义
📄 MyManualServiceStub.java — 存根抽象类
📄 MyManualServiceProxy.java — 代理实现类
📄 ManualBinderService.java — 服务端 Service

📁 client (客户端)
📄 MainActivity.kt — 绑定服务并调用

⚠️ 注意事项: 客户端需要将 IMyManualService、MyManualServiceStub、MyManualServiceProxy 这三个文件原样复制到客户端工程中,保证两端接口完全一致。


三、定义接口:IMyManualService

首先定义 AIDL 中常见的 IInterface 接口。这个接口包含两个核心要素:

  • DESCRIPTOR:Binder 服务的唯一标识符,用于客户端查询本地接口
  • 业务方法:定义服务端暴露给客户端调用的方法

IMyManualService.java

package com.qhsoft.foodsafety.module;

import android.os.IInterface;
import android.os.RemoteException;

public interface IMyManualService extends IInterface {
   // 唯一标识符,用于区分不同的 Binder 服务
   // 这个字符串必须全局唯一,建议用包名+接口名的全限定名
   String DESCRIPTOR = \”com.qhsoft.foodsafety.module.IMyManualService\”;

   // 定义远程方法:两数相加
   int add(int a, int b) throws RemoteException;

   // 定义远程方法:打招呼
   String sayHello(String name) throws RemoteException;
}

💡 为什么继承 IInterface? IInterface 是 Android 为 Binder 接口定义的基础接口,它只有一个方法 asBinder(),用于获取底层的 IBinder 对象。所有 AIDL 生成的接口都继承自它。


四、手写 Stub:MyManualServiceStub

Stub 是 Binder 通信的服务端入口。它继承 Binder 并实现自定义接口,负责接收客户端发来的请求,并分发给具体的业务实现。

Stub 的核心职责

  • 定义事务码(TRANSACTION_code),每个方法对应一个唯一整型 ID
  • 实现 asInterface(),判断同进程还是跨进程
  • 重写 onTransact(),解析客户端数据并调用本地实现
  • MyManualServiceStub.java

    package com.qhsoft.foodsafety.module;

    import android.os.Binder;
    import android.os.IBinder;
    import android.os.IInterface;
    import android.os.Parcel;
    import android.os.RemoteException;

    public abstract class MyManualServiceStub extends Binder implements IMyManualService {

       // 事务码:客户端和服务端必须完全一致
       // 这里的 1、2 就是方法的\”身份证\”
       static final int TRANSACTION_add = 1;
       static final int TRANSACTION_sayHello = 2;

       public MyManualServiceStub() {
           // 将当前 Binder 对象和描述符绑定
           // 这样客户端 queryLocalInterface 时才能找到它
           this.attachInterface(this, DESCRIPTOR);
      }

       @Override
       public IBinder asBinder() {
         

    赞(0)
    未经允许不得转载:171主机测评 » 不用 AIDL,手把手教你手写 Binder 代理类
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址