android AIDL

AIDL Demo

AIDL文件

// 定义一个 IAdd.aidl 文件,声明一个接口
package com.example.aidldemo;

interface IAdd {
    // 定义一个 add 方法,接收两个 int 类型的参数,返回一个 int 类型的结果
    int add(int x, int y);
}

服务器端文件

AddService.java

// 在服务端的 AddService.java 中,重写 onBind 方法,返回从 Intent 中获取的 Binder 对象
package com.example.aidldemo;

import android.app.Service;
import android.content.Intent;
import android.os.IBinder;

public class AddService extends Service {

    @Override
    public IBinder onBind(Intent intent) {
        // 从 Intent 中获取 Binder 对象,并返回
        return intent.getParcelableExtra("binder");
    }
}

MainActivity.java

// 在服务端的 MainActivity.java 中,实现 IAdd 接口,并创建一个 Binder 对象
package com.example.aidldemo;

import androidx.appcompat.app.AppCompatActivity;

import android.content.Intent;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;

public class MainActivity extends AppCompatActivity {

    private static final String TAG = "MainActivity";

    private EditText etX, etY;
    private Button btnAdd;

    // 实现 IAdd 接口,并创建一个 Binder 对象
    private IBinder mBinder = new IAdd.Stub() {
        @Override
        public int add(int x, int y) throws RemoteException {
            return x + y;
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        etX = findViewById(R.id.et_add_x);
        etY = findViewById(R.id.et_add_y);
        btnAdd = findViewById(R.id.btn_add);

        // 启动服务,并传递 Binder 对象
        Intent intent = new Intent(this, AddService.class);
        intent.putExtra("binder", mBinder);
        startService(intent);

        // 设置按钮点击事件,获取输入的两个数,并调用 Binder 对象的 add 方法,打印结果
        btnAdd.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                try {
                    int x = Integer.parseInt(etX.getText().toString());
                    int y = Integer.parseInt(etY.getText().toString());
                    int result = mBinder.add(x, y);
                    Log.d(TAG, "result: " + result);
                } catch (NumberFormatException | RemoteException e) {
                    e.printStackTrace();
                }
            }
        });
    }
}

客服端

// 在客户端的 MainActivity.java 中,绑定服务,并获取 Binder 对象,调用其 add 方法,打印结果
package com.example.client;

import androidx.appcompat.app.AppCompatActivity;

import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;

import com.example.aidldemo.IAdd;

public class MainActivity extends AppCompatActivity {

    private static final String TAG = "MainActivity";

    private IAdd mIAdd; // 声明一个 IAdd 接口的变量

    // 创建一个 ServiceConnection 对象,用于绑定服务和获取 Binder 对象
    private ServiceConnection mConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            // 将 IBinder 对象转换为 IAdd 接口,并赋值给 mIAdd 变量
            mIAdd = IAdd.Stub.asInterface(service);
            try {
                // 调用 mIAdd 的 add 方法,并打印结果
                int result = mIAdd.add(3, 5);
                Log.d(TAG, "result: " + result);
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {

        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // 创建一个 Intent 对象,指定要绑定的服务的包名和类名
        Intent intent = new Intent();
        intent.setComponent(new ComponentName("com.example.aidldemo", "com.example.aidldemo.AddService"));

        // 绑定服务,并传递 ServiceConnection 对象
        bindService(intent, mConnection, BIND_AUTO_CREATE);
    }
}

AIDL 自动生成代码

这是一个 IAdd.java 文件,是由 IAdd.aidl 文件自动生成的。它主要包含以下几个部分:

IAdd 接口:定义了一个 add 方法,用于接收两个 int 类型的参数,返回一个 int 类型的结果。
Stub 类:继承自 Binder 类,实现了 IAdd 接口,用于在服务端创建 Binder 对象,并处理来自客户端的事务请求。
Proxy 类:实现了 IAdd 接口,用于在客户端创建代理对象,并通过 transact 方法向服务端发送事务请求,并接收回复。
TRANSACTION_add 常量:表示 add 方法的事务码,用于区分不同的方法调用。
DESCRIPTOR 常量:表示接口描述符,用于标识不同的接口类型。

// 这是一个 IAdd.java 文件,是由 IAdd.aidl 文件自动生成的
package com.example.aidldemo;

// 导入一些必要的类
import android.os.Binder;
import android.os.IBinder;
import android.os.IInterface;
import android.os.Parcel;
import android.os.RemoteException;

// 定义一个 IAdd 接口,继承自 IInterface 接口
public interface IAdd extends IInterface {
    // 定义一个常量,表示接口描述符
    public static final String DESCRIPTOR = "com.example.aidldemo.IAdd";

    // 定义一个常量,表示 add 方法的事务码
    public static final int TRANSACTION_add = IBinder.FIRST_CALL_TRANSACTION + 0;

    // 声明一个 add 方法,抛出 RemoteException 异常
    public int add(int x, int y) throws RemoteException;

    // 定义一个 Stub 类,继承自 Binder 类,实现 IAdd 接口
    public static abstract class Stub extends Binder implements IAdd {
        // 定义一个常量,表示接口描述符
        private static final String DESCRIPTOR = "com.example.aidldemo.IAdd";

        // 构造方法,将接口描述符设置为 Binder 的标识符
        public Stub() {
            this.attachInterface(this, DESCRIPTOR);
        }

        // 静态方法,将 IBinder 对象转换为 IAdd 接口,并返回
        public static IAdd asInterface(IBinder obj) {
            if ((obj == null)) {
                return null;
            }
            // 获取 Binder 对象关联的接口代理对象
            IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
            if (((iin != null) && (iin instanceof IAdd))) {
                // 如果是本地 Binder 对象,则直接返回接口对象
                return ((IAdd) iin);
            }
            // 否则返回一个代理对象,用于远程调用
            return new Proxy(obj);
        }

        @Override
        public IBinder asBinder() {
            return this;
        }

        @Override
        public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
            switch (code) {
                case INTERFACE_TRANSACTION: {
                    // 如果是获取接口描述符的事务,则将描述符写入回复数据中,并返回 true
                    reply.writeString(DESCRIPTOR);
                    return true;
                }
                case TRANSACTION_add: {
                    // 如果是 add 方法的事务,则先检查数据包是否有足够的数据,并读取接口描述符
                    data.enforceInterface(DESCRIPTOR);
                    // 从数据包中读取两个 int 类型的参数
                    int x = data.readInt();
                    int y = data.readInt();
                    // 调用 add 方法,并获取结果
                    int result = this.add(x, y);
                    // 将结果写入回复数据中,并标记成功
                    reply.writeNoException();
                    reply.writeInt(result);
                    return true;
                }
                default: {
                    // 其他情况交给父类处理
                    return super.onTransact(code, data, reply, flags);
                }
            }
        }

        // 定义一个 Proxy 类,实现 IAdd 接口
        private static class Proxy implements IAdd {
            private IBinder mRemote; // 声明一个 IBinder 对象的变量

            Proxy(IBinder remote) {
                mRemote = remote; // 构造方法,传入一个 IBinder 对象,并赋值给变量
            }

            @Override
            public IBinder asBinder() {
                return mRemote; // 返回 IBinder 对象
            }

            public String getInterfaceDescriptor() {
                return DESCRIPTOR; // 返回接口描述符
            }

            @Override
            public int add(int x, int y) throws RemoteException {
                Parcel data = Parcel.obtain(); // 获取一个空的数据包对象
                Parcel reply = Parcel.obtain(); // 获取一个空的回复数据包对象
                int result; // 声明一个 int 类型的变量,用于存储结果
                try {
                    data.writeInterfaceToken(DESCRIPTOR); // 将接口描述符写入数据包中
                    data.writeInt(x); // 将第一个参数写入数据包中
                    data.writeInt(y); // 将第二个参数写入数据包中
                    mRemote.transact(Stub.TRANSACTION_add, data, reply, 0); // 调用 transact 方法,将数据包发送给远程 Binder 对象,并等待回复
                    reply.readException(); // 从回复数据包中读取异常信息,如果有异常则抛出
                    result = reply.readInt(); // 从回复数据包中读取结果,并赋值给变量
                } finally {
                    data.recycle(); // 回收数据包对象
                    reply.recycle(); // 回收回复数据包对象
                }
                return result; // 返回结果
            }
        }
    }
}

调用逻辑

客户端 Proxy Stub 服务端 创建 Intent 对象,指定服务的包名和类名 创建 ServiceConnection 对象 调用 bindService 方法,绑定服务 实现 IAdd 接口,并创建 Binder 对象 启动服务,并传递 Binder 对象 重写 onBind 方法,返回 Binder 对象 将 Binder 对象转换为 IAdd 接口,并赋值给变量 创建 Proxy 对象,传入 Binder 对象 调用 IAdd 接口的 add 方法,并获取结果 创建数据包对象和回复数据包对象,并将接口描述符和参数写入数据包中 调用 Binder 对象的 transact 方法,将数据包发送给远程 Binder 对象,并等待回复 重写 onTransact 方法,根据事务码,从数据包中读取参数,并调用相应的接口方法,并将结果写入回复数据包中 从回复数据包中读取异常信息和结果,并返回结果 客户端 Proxy Stub 服务端
  • 客户端:客户端是指需要使用服务端提供的功能或数据的应用组件,例如一个 Activity。客户端需要做以下几件事:
    • 创建一个 Intent 对象,指定要绑定的服务的包名和类名。
    • 创建一个 ServiceConnection 对象,用于绑定服务和获取 Binder 对象。
    • 调用 bindService 方法,传入 Intent 对象和 ServiceConnection 对象,绑定服务。
    • 在 ServiceConnection 对象的 onServiceConnected 方法中,将 IBinder 对象转换为 IAdd 接口,并赋值给一个变量。
    • 调用 IAdd 接口的 add 方法,并获取结果。
  • 生成代码:生成代码是指由 aidl 工具根据 IAdd.aidl 文件自动生成的 IAdd.java 文件。生成代码主要包含以下几个部分:
    • IAdd 接口:定义了一个 add 方法,用于接收两个 int 类型的参数,返回一个 int 类型的结果。
    • Stub 类:继承自 Binder 类,实现了 IAdd 接口,用于在服务端创建 Binder 对象,并处理来自客户端的事务请求。
    • Proxy 类:实现了 IAdd 接口,用于在客户端创建代理对象,并通过 transact 方法向服务端发送事务请求,并接收回复。
    • TRANSACTION_add 常量:表示 add 方法的事务码,用于区分不同的方法调用。
    • DESCRIPTOR 常量:表示接口描述符,用于标识不同的接口类型。
  • Stub 类:Stub 类是生成代码中的一个内部抽象类,它继承自 Binder 类,并实现了 IAdd 接口。Stub 类主要做以下几件事:
    • 构造方法:将接口描述符设置为 Binder 的标识符。
    • 静态方法 asInterface :将 IBinder 对象转换为 IAdd 接口,并返回。如果是本地 Binder 对象,则直接返回接口对象;否则返回一个 Proxy 对象。
    • 实例方法 asBinder :返回自身对象。
    • 实例方法 onTransact :重写 Binder 的 onTransact 方法,用于处理来自客户端的事务请求。根据不同的事务码,从数据包中读取参数,并调用相应的接口方法,并将结果写入回复数据包中。
  • Proxy 类:Proxy 类是生成代码中的一个内部类,它实现了 IAdd 接口。Proxy 类主要做以下几件事:
    • 构造方法:传入一个 IBinder 对象,并赋值给一个变量。
    • 实例方法 asBinder :返回 IBinder 对象。
    • 实例方法 getInterfaceDescriptor :返回接口描述符。
    • 实例方法 add :实现 IAdd 接口的 add 方法。创建一个空的数据包对象和回复数据包对象,并将接口描述符和参数写入数据包中。调用 IBinder 对象的 transact 方法,将数据包发送给远程 Binder 对象,并等待回复。从回复数据包中读取异常信息和结果,并返回结果。

源: 与必应的对话, 2023/6/20
(1) Generating C++ Binder Interfaces with aidl-cpp - Google Open Source. https://android.googlesource.com/platform/system/tools/aidl/+/brillo-m10-dev/docs/aidl-cpp.md.
(2) Android Interface Definition Language (AIDL). https://developer.android.com/guide/components/aidl.
(3) What is " Stub " and “AIDL” for in java? - Stack Overflow. https://stackoverflow.com/questions/10648280/what-is-stub-and-aidl-for-in-java.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值