Android Binder 用法详解

06-01 1567阅读

Binder 是 Android 系统中的一种进程间通信(IPC)机制,它允许不同进程之间进行高效通信。Binder 在 Android 系统中被广泛使用,例如在 Activity 与 Service 的交互中。

Binder 的基本组成

实现 Binder 通信通常包含以下几个关键部分:

  1. AIDL 接口定义:通过 Android Interface Definition Language 定义接口
  2. 服务端实现:实现 AIDL 接口并在 Service 中提供服务
  3. 客户端调用:绑定服务并调用远程方法

下面通过一个完整的示例来展示 Binder 的使用方法。

示例:创建一个计算器服务

第一步:定义 AIDL 接口

创建文件 ICalculator.aidl:

// ICalculator.aidl
package com.example.binderexample;
interface ICalculator {
    int add(int a, int b);
    int subtract(int a, int b);
    int multiply(int a, int b);
    int divide(int a, int b);
}

第二步:创建服务端 Service

// CalculatorService.java
package com.example.binderexample;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
public class CalculatorService extends Service {
    private static final String TAG = "CalculatorService";
    // Binder 实现
    private final ICalculator.Stub mBinder = new ICalculator.Stub() {
        @Override
        public int add(int a, int b) throws RemoteException {
            Log.d(TAG, "add() called with: a = [" + a + "], b = [" + b + "]");
            return a + b;
        }
        @Override
        public int subtract(int a, int b) throws RemoteException {
            Log.d(TAG, "subtract() called with: a = [" + a + "], b = [" + b + "]");
            return a - b;
        }
        @Override
        public int multiply(int a, int b) throws RemoteException {
            Log.d(TAG, "multiply() called with: a = [" + a + "], b = [" + b + "]");
            return a * b;
        }
        @Override
        public int divide(int a, int b) throws RemoteException {
            Log.d(TAG, "divide() called with: a = [" + a + "], b = [" + b + "]");
            if (b == 0) {
                throw new RemoteException("Division by zero");
            }
            return a / b;
        }
    };
    @Override
    public IBinder onBind(Intent intent) {
        Log.d(TAG, "onBind: Service bound");
        return mBinder;
    }
}

第三步:在 AndroidManifest.xml 中注册服务

    
        
    

第四步:客户端实现

// MainActivity.java
package com.example.binderexample;
import android.content.ComponentName;
import android.content.Context;
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 android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
public class MainActivity extends AppCompatActivity {
    private static final String TAG = "MainActivity";
    private EditText mNum1EditText, mNum2EditText;
    private TextView mResultTextView;
    private Button mAddButton, mSubtractButton, mMultiplyButton, mDivideButton;
    private ICalculator mCalculator;
    private boolean mBound = false;
    // 服务连接对象
    private ServiceConnection mConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            mCalculator = ICalculator.Stub.asInterface(service);
            mBound = true;
            Log.d(TAG, "onServiceConnected: Service connected");
            Toast.makeText(MainActivity.this, "Calculator Service Connected", Toast.LENGTH_SHORT).show();
        }
        @Override
        public void onServiceDisconnected(ComponentName name) {
            mCalculator = null;
            mBound = false;
            Log.d(TAG, "onServiceDisconnected: Service disconnected");
        }
    };
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        // 初始化 UI 组件
        mNum1EditText = findViewById(R.id.editText_num1);
        mNum2EditText = findViewById(R.id.editText_num2);
        mResultTextView = findViewById(R.id.textView_result);
        mAddButton = findViewById(R.id.button_add);
        mSubtractButton = findViewById(R.id.button_subtract);
        mMultiplyButton = findViewById(R.id.button_multiply);
        mDivideButton = findViewById(R.id.button_divide);
        // 添加按钮点击事件
        mAddButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                performOperation("add");
            }
        });
        mSubtractButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                performOperation("subtract");
            }
        });
        mMultiplyButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                performOperation("multiply");
            }
        });
        mDivideButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                performOperation("divide");
            }
        });
    }
    private void performOperation(String operation) {
        if (!mBound) {
            Toast.makeText(this, "Service not bound", Toast.LENGTH_SHORT).show();
            return;
        }
        try {
            // 获取输入值
            int num1 = Integer.parseInt(mNum1EditText.getText().toString());
            int num2 = Integer.parseInt(mNum2EditText.getText().toString());
            int result = 0;
            // 执行远程操作
            switch (operation) {
                case "add":
                    result = mCalculator.add(num1, num2);
                    break;
                case "subtract":
                    result = mCalculator.subtract(num1, num2);
                    break;
                case "multiply":
                    result = mCalculator.multiply(num1, num2);
                    break;
                case "divide":
                    result = mCalculator.divide(num1, num2);
                    break;
            }
            // 显示结果
            mResultTextView.setText("结果: " + result);
        } catch (RemoteException e) {
            Log.e(TAG, "RemoteException: " + e.getMessage());
            Toast.makeText(this, "Remote exception: " + e.getMessage(), Toast.LENGTH_SHORT).show();
        } catch (NumberFormatException e) {
            Toast.makeText(this, "Please enter valid numbers", Toast.LENGTH_SHORT).show();
        }
    }
    @Override
    protected void onStart() {
        super.onStart();
        // 绑定服务
        Intent intent = new Intent();
        intent.setAction("com.example.binderexample.ICalculator");
        intent.setPackage(getPackageName());
        bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
    }
    @Override
    protected void onStop() {
        super.onStop();
        // 解绑服务
        if (mBound) {
            unbindService(mConnection);
            mBound = false;
        }
    }
}

第五步:布局文件



    
    
    
        
        
        
        
    
    

Binder 工作原理解释

  1. AIDL 编译:编译时,Android 工具会根据 AIDL 文件生成相应的 Java 接口,其中包含一个内部抽象类 Stub,继承自 Binder 并实现了该接口

  2. Stub 类:

    • 服务端继承并实现 Stub 类的抽象方法
    • Stub 类拥有 asInterface() 静态方法,用于将 IBinder 转换为接口类型
    • 通信过程:

      • 客户端调用 bindService() 绑定服务
      • 服务端返回 Binder 对象
      • 客户端通过 Stub.asInterface() 将 Binder 对象转换为接口
      • 客户端调用接口方法,实际上是通过 Binder 驱动进行跨进程通信

高级用法:传输复杂对象

如果需要传输复杂对象,需要实现 Parcelable 接口:

// Person.java
package com.example.binderexample;
import android.os.Parcel;
import android.os.Parcelable;
public class Person implements Parcelable {
    private String name;
    private int age;
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
    protected Person(Parcel in) {
        name = in.readString();
        age = in.readInt();
    }
    public String getName() {
        return name;
    }
    public int getAge() {
        return age;
    }
    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeString(name);
        dest.writeInt(age);
    }
    @Override
    public int describeContents() {
        return 0;
    }
    public static final Creator CREATOR = new Creator() {
        @Override
        public Person createFromParcel(Parcel in) {
            return new Person(in);
        }
        @Override
        public Person[] newArray(int size) {
            return new Person[size];
        }
    };
}

然后在 AIDL 文件中引用这个类:

// Person.aidl
package com.example.binderexample;
parcelable Person;
// IPersonService.aidl
package com.example.binderexample;
import com.example.binderexample.Person;
interface IPersonService {
    void addPerson(in Person person);
    List getAllPersons();
}

Android C++ 中的 Binder 使用

在 Android C++ 层也可以使用 Binder 进行进程间通信。实际上,Android 框架中的核心 Binder 实现就是用 C++ 编写的,位于 native 层。C++ 中的 Binder 框架是 Java Binder 框架的基础。

Android Native Binder 主要组件

在 C++ 层使用 Binder 主要涉及以下几个关键类:

  1. IBinder:表示一个 Binder 对象的基类
  2. BpBinder:代理端的 Binder 实现(客户端)
  3. BBinder:本地端的 Binder 实现(服务端)
  4. BnInterface:服务端接口模板类
  5. BpInterface:客户端接口模板类
  6. IInterface:Binder 接口的基类
  7. ProcessState:管理进程的 Binder 状态
  8. IPCThreadState:管理线程的 Binder 状态

C++ Binder 实现示例

下面是一个完整的 C++ Binder 示例,包括服务端和客户端。

第一步:定义接口

首先,我们需要定义一个计算器服务的接口:

// ICalculator.h
#ifndef ICALCULATOR_H
#define ICALCULATOR_H
#include 
#include 
namespace android {
// 接口标识符
enum {
    CALCULATOR_ADD = IBinder::FIRST_CALL_TRANSACTION,
    CALCULATOR_SUBTRACT,
    CALCULATOR_MULTIPLY,
    CALCULATOR_DIVIDE
};
// 接口定义
class ICalculator : public IInterface {
public:
    DECLARE_META_INTERFACE(Calculator); // 声明接口元信息
    
    // 纯虚函数,需要子类实现
    virtual int32_t add(int32_t a, int32_t b) = 0;
    virtual int32_t subtract(int32_t a, int32_t b) = 0;
    virtual int32_t multiply(int32_t a, int32_t b) = 0;
    virtual int32_t divide(int32_t a, int32_t b) = 0;
};
// 服务端接口
class BnCalculator : public BnInterface {
public:
    // onTransact 函数处理来自客户端的请求
    virtual status_t onTransact(uint32_t code, const Parcel& data,
                               Parcel* reply, uint32_t flags = 0);
};
} // namespace android
#endif // ICALCULATOR_H

第二步:实现接口

接下来,我们需要实现这个接口:

// ICalculator.cpp
#include "ICalculator.h"
namespace android {
// 实现元接口宏
IMPLEMENT_META_INTERFACE(Calculator, "android.calculator.ICalculator");
// 处理远程调用请求
status_t BnCalculator::onTransact(uint32_t code, const Parcel& data,
                               Parcel* reply, uint32_t flags) {
    switch (code) {
        case CALCULATOR_ADD: {
            CHECK_INTERFACE(ICalculator, data, reply);
            int32_t a = data.readInt32();
            int32_t b = data.readInt32();
            int32_t result = add(a, b);
            reply->writeInt32(result);
            return NO_ERROR;
        }
        case CALCULATOR_SUBTRACT: {
            CHECK_INTERFACE(ICalculator, data, reply);
            int32_t a = data.readInt32();
            int32_t b = data.readInt32();
            int32_t result = subtract(a, b);
            reply->writeInt32(result);
            return NO_ERROR;
        }
        case CALCULATOR_MULTIPLY: {
            CHECK_INTERFACE(ICalculator, data, reply);
            int32_t a = data.readInt32();
            int32_t b = data.readInt32();
            int32_t result = multiply(a, b);
            reply->writeInt32(result);
            return NO_ERROR;
        }
        case CALCULATOR_DIVIDE: {
            CHECK_INTERFACE(ICalculator, data, reply);
            int32_t a = data.readInt32();
            int32_t b = data.readInt32();
            if (b == 0) {
                return BAD_VALUE; // 除数为零错误
            }
            int32_t result = divide(a, b);
            reply->writeInt32(result);
            return NO_ERROR;
        }
        default:
            return BBinder::onTransact(code, data, reply, flags);
    }
}
// 客户端代理实现
class BpCalculator : public BpInterface {
public:
    BpCalculator(const sp& impl) : BpInterface(impl) {}
    virtual int32_t add(int32_t a, int32_t b) {
        Parcel data, reply;
        data.writeInterfaceToken(ICalculator::getInterfaceDescriptor());
        data.writeInt32(a);
        data.writeInt32(b);
        
        remote()->transact(CALCULATOR_ADD, data, &reply);
        return reply.readInt32();
    }
    virtual int32_t subtract(int32_t a, int32_t b) {
        Parcel data, reply;
        data.writeInterfaceToken(ICalculator::getInterfaceDescriptor());
        data.writeInt32(a);
        data.writeInt32(b);
        
        remote()->transact(CALCULATOR_SUBTRACT, data, &reply);
        return reply.readInt32();
    }
    virtual int32_t multiply(int32_t a, int32_t b) {
        Parcel data, reply;
        data.writeInterfaceToken(ICalculator::getInterfaceDescriptor());
        data.writeInt32(a);
        data.writeInt32(b);
        
        remote()->transact(CALCULATOR_MULTIPLY, data, &reply);
        return reply.readInt32();
    }
    virtual int32_t divide(int32_t a, int32_t b) {
        Parcel data, reply;
        data.writeInterfaceToken(ICalculator::getInterfaceDescriptor());
        data.writeInt32(a);
        data.writeInt32(b);
        
        status_t status = remote()->transact(CALCULATOR_DIVIDE, data, &reply);
        if (status != NO_ERROR) {
            return -1; // 错误处理
        }
        return reply.readInt32();
    }
};
} // namespace android

第三步:实现服务端

服务端需要实现 ICalculator 接口,并提供一个服务:

Android Binder 用法详解
(图片来源网络,侵删)
// CalculatorService.h
#ifndef CALCULATOR_SERVICE_H
#define CALCULATOR_SERVICE_H
#include "ICalculator.h"
namespace android {
class CalculatorService : public BnCalculator {
public:
    static void instantiate(); // 用于注册服务
    
    // 实现ICalculator接口的方法
    virtual int32_t add(int32_t a, int32_t b);
    virtual int32_t subtract(int32_t a, int32_t b);
    virtual int32_t multiply(int32_t a, int32_t b);
    virtual int32_t divide(int32_t a, int32_t b);
};
} // namespace android
#endif // CALCULATOR_SERVICE_H
// CalculatorService.cpp
#include "CalculatorService.h"
#include 
#include 
namespace android {
void CalculatorService::instantiate() {
    sp sm = defaultServiceManager();
    sm->addService(String16("calculator"), new CalculatorService());
    ALOGI("Calculator service started");
}
int32_t CalculatorService::add(int32_t a, int32_t b) {
    ALOGI("add() called with: a = %d, b = %d", a, b);
    return a + b;
}
int32_t CalculatorService::subtract(int32_t a, int32_t b) {
    ALOGI("subtract() called with: a = %d, b = %d", a, b);
    return a - b;
}
int32_t CalculatorService::multiply(int32_t a, int32_t b) {
    ALOGI("multiply() called with: a = %d, b = %d", a, b);
    return a * b;
}
int32_t CalculatorService::divide(int32_t a, int32_t b) {
    ALOGI("divide() called with: a = %d, b = %d", a, b);
    return a / b;
}
} // namespace android

第四步:服务端主程序

编写服务端主程序,用于启动服务:

// server_main.cpp
#include 
#include 
#include 
#include "CalculatorService.h"
using namespace android;
int main() {
    sp proc(ProcessState::self());
    
    // 实例化并注册服务
    CalculatorService::instantiate();
    
    // 启动线程池处理请求
    ProcessState::self()->startThreadPool();
    IPCThreadState::self()->joinThreadPool();
    
    return 0;
}

第五步:客户端实现

客户端程序示例:

Android Binder 用法详解
(图片来源网络,侵删)
// client_main.cpp
#include 
#include 
#include 
#include "ICalculator.h"
using namespace android;
using namespace std;
int main() {
    sp sm = defaultServiceManager();
    
    // 获取计算器服务
    sp binder = sm->getService(String16("calculator"));
    if (binder == nullptr) {
        ALOGE("Failed to get calculator service");
        return -1;
    }
    
    // 创建代理对象
    sp calculator = interface_cast(binder);
    
    // 使用计算器服务
    int a = 10, b = 5;
    
    cout 
    static {
        System.loadLibrary("nativebinderhelper");
    }
    
    // 本地方法声明
    public static native int addNumbers(int a, int b);
    public static native int subtractNumbers(int a, int b);
}

    sp
        return -1;
    }
    
    sp
    sp
        return -1;
    }
    
    sp
免责声明:我们致力于保护作者版权,注重分享,被刊用文章因无法核实真实出处,未能及时与作者取得联系,或有版权异议的,请联系管理员,我们会立即处理! 部分文章是来自自研大数据AI进行生成,内容摘自(百度百科,百度知道,头条百科,中国民法典,刑法,牛津词典,新华词典,汉语词典,国家院校,科普平台)等数据,内容仅供学习参考,不准确地方联系删除处理! 图片声明:本站部分配图来自人工智能系统AI生成,觅知网授权图片,PxHere摄影无版权图库和百度,360,搜狗等多加搜索引擎自动关键词搜索配图,如有侵权的图片,请第一时间联系我们。

目录[+]

取消
微信二维码
微信二维码
支付宝二维码