Android Binder 详解与实践指南
1. Binder 基础概念
1.1 什么是 Binder?
Binder 是 Android 系统中最重要的进程间通信(IPC)机制,它具有以下特点:
- 高性能:相比其他 IPC 机制,Binder 只需要一次数据拷贝
- 安全性:基于 C/S 架构,支持身份验证
- 面向对象:可以像调用本地方法一样调用远程方法
1.2 Binder 架构组件
Client Process → Binder Driver → Server Process
↓ ↓
Binder Proxy Binder Object
2. Binder 基础实例
2.1 简单的 Binder 服务端
java
// SimpleBinderService.java
package com.example.binderdemo;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
public class SimpleBinderService extends Service {
private static final String TAG = "SimpleBinderService";
// 定义 AIDL 接口的实现
private final ISimpleService.Stub binder = new ISimpleService.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 String greet(String name) throws RemoteException {
Log.d(TAG, "greet() called with: name = " + name);
return "Hello, " + name + "! from Binder Service";
}
@Override
public void sendData(DataModel data) throws RemoteException {
Log.d(TAG, "sendData() called with: " + data.toString());
// 处理数据...
}
};
@Override
public IBinder onBind(Intent intent) {
Log.d(TAG, "onBind() called");
return binder;
}
@Override
public void onCreate() {
super.onCreate();
Log.d(TAG, "Service created");
}
@Override
public void onDestroy() {
super.onDestroy();
Log.d(TAG, "Service destroyed");
}
}
2.2 定义 AIDL 接口
java
// ISimpleService.aidl
package com.example.binderdemo;
// 定义数据模型
parcelable DataModel;
interface ISimpleService {
int add(int a, int b);
String greet(String name);
void sendData(in DataModel data);
}
2.3 数据模型定义
java
// DataModel.java
package com.example.binderdemo;
import android.os.Parcel;
import android.os.Parcelable;
public class DataModel implements Parcelable {
public int id;
public String message;
public long timestamp;
public DataModel() {}
public DataModel(int id, String message) {
this.id = id;
this.message = message;
this.timestamp = System.currentTimeMillis();
}
protected DataModel(Parcel in) {
id = in.readInt();
message = in.readString();
timestamp = in.readLong();
}
public static final Creator<DataModel> CREATOR = new Creator<DataModel>() {
@Override
public DataModel createFromParcel(Parcel in) {
return new DataModel(in);
}
@Override
public DataModel[] newArray(int size) {
return new DataModel[size];
}
};
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(id);
dest.writeString(message);
dest.writeLong(timestamp);
}
@Override
public String toString() {
return "DataModel{" +
"id=" + id +
", message='" + message + '\'' +
", timestamp=" + timestamp +
'}';
}
}
2.4 客户端实现
java
// MainActivity.java
package com.example.binderdemo;
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.widget.Button;
import android.widget.TextView;
import androidx.appcompat.app.AppCompatActivity;
public class MainActivity extends AppCompatActivity {
private static final String TAG = "MainActivity";
private ISimpleService simpleService;
private boolean isBound = false;
private TextView resultText;
private ServiceConnection connection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
Log.d(TAG, "Service connected");
simpleService = ISimpleService.Stub.asInterface(service);
isBound = true;
updateStatus("Service Connected");
}
@Override
public void onServiceDisconnected(ComponentName name) {
Log.d(TAG, "Service disconnected");
simpleService = null;
isBound = false;
updateStatus("Service Disconnected");
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
resultText = findViewById(R.id.result_text);
Button bindBtn = findViewById(R.id.bind_btn);
Button unbindBtn = findViewById(R.id.unbind_btn);
Button testBtn = findViewById(R.id.test_btn);
bindBtn.setOnClickListener(v -> bindService());
unbindBtn.setOnClickListener(v -> unbindService());
testBtn.setOnClickListener(v -> testService());
}
private void bindService() {
Intent intent = new Intent(this, SimpleBinderService.class);
bindService(intent, connection, Context.BIND_AUTO_CREATE);
updateStatus("Binding Service...");
}
private void unbindService() {
if (isBound) {
unbindService(connection);
isBound = false;
simpleService = null;
updateStatus("Service Unbound");
}
}
private void testService() {
if (!isBound || simpleService == null) {
updateStatus("Service not bound!");
return;
}
new Thread(() -> {
try {
// 测试加法
int result = simpleService.add(5, 3);
String message = "5 + 3 = " + result;
// 测试问候
String greeting = simpleService.greet("Android Developer");
// 测试数据传输
DataModel data = new DataModel(1, "Test Message");
simpleService.sendData(data);
runOnUiThread(() -> updateStatus(
message + "\n" +
greeting + "\n" +
"Data sent: " + data.toString()
));
} catch (RemoteException e) {
runOnUiThread(() -> updateStatus("Error: " + e.getMessage()));
Log.e(TAG, "RemoteException: ", e);
}
}).start();
}
private void updateStatus(String text) {
resultText.setText(text);
Log.d(TAG, text);
}
@Override
protected void onDestroy() {
super.onDestroy();
if (isBound) {
unbindService();
}
}
}
2.5 布局文件
xml
<!-- activity_main.xml -->
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="16dp">
<Button
android:id="@+id/bind_btn"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Bind Service" />
<Button
android:id="@+id/unbind_btn"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Unbind Service" />
<Button
android:id="@+id/test_btn"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Test Service" />
<TextView
android:id="@+id/result_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:padding="16dp"
android:background="#f0f0f0"
android:text="Status: Not connected"
android:textSize="14sp" />
</LinearLayout>
2.6 AndroidManifest 配置
xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.binderdemo">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service
android:name=".SimpleBinderService"
android:enabled="true"
android:exported="false" />
</application>
</manifest>
3. 运行结果分析
首次运行应用:
MainActivity: Status: Not connected
点击 "Bind Service" 按钮:
SimpleBinderService: Service created
SimpleBinderService: onBind() called
MainActivity: Service connected
MainActivity: Status: Service Connected
点击 "Test Service" 按钮:
SimpleBinderService: add() called with: a = 5, b = 3
SimpleBinderService: greet() called with: name = Android Developer
SimpleBinderService: sendData() called with: DataModel{id=1, message='Test Message', timestamp=1641234567890}
MainActivity: 5 + 3 = 8
Hello, Android Developer! from Binder Service
Data sent: DataModel{id=1, message='Test Message', timestamp=1641234567890}
点击 "Unbind Service" 按钮:
SimpleBinderService: Service destroyed
MainActivity: Service Unbound
4. 高级 Binder 特性
4.1 带回调的 Binder 服务
java
// ICallbackService.aidl
package com.example.binderdemo;
interface ICallbackService {
void registerCallback(ICallback callback);
void unregisterCallback(ICallback callback);
void startTask(int taskId);
}
interface ICallback {
void onTaskStarted(int taskId);
void onTaskProgress(int taskId, int progress);
void onTaskCompleted(int taskId, String result);
}
4.2 回调服务实现
java
// CallbackBinderService.java
public class CallbackBinderService extends Service {
private static final String TAG = "CallbackBinderService";
private final List<ICallback> callbacks = new CopyOnWriteArrayList<>();
private final ICallbackService.Stub binder = new ICallbackService.Stub() {
@Override
public void registerCallback(ICallback callback) throws RemoteException {
if (callback != null && !callbacks.contains(callback)) {
callbacks.add(callback);
Log.d(TAG, "Callback registered, total: " + callbacks.size());
}
}
@Override
public void unregisterCallback(ICallback callback) throws RemoteException {
callbacks.remove(callback);
Log.d(TAG, "Callback unregistered, total: " + callbacks.size());
}
@Override
public void startTask(int taskId) throws RemoteException {
Log.d(TAG, "Starting task: " + taskId);
new TaskExecutor(taskId).start();
}
};
private class TaskExecutor extends Thread {
private final int taskId;
TaskExecutor(int taskId) {
this.taskId = taskId;
}
@Override
public void run() {
try {
// 通知任务开始
for (ICallback callback : callbacks) {
callback.onTaskStarted(taskId);
}
// 模拟任务执行
for (int i = 0; i <= 100; i += 10) {
Thread.sleep(200);
// 更新进度
for (ICallback callback : callbacks) {
callback.onTaskProgress(taskId, i);
}
}
// 任务完成
for (ICallback callback : callbacks) {
callback.onTaskCompleted(taskId, "Task " + taskId + " completed successfully");
}
} catch (Exception e) {
Log.e(TAG, "Task execution failed", e);
}
}
}
@Override
public IBinder onBind(Intent intent) {
return binder;
}
}
4.3 客户端回调处理
java
// 在 MainActivity 中添加回调处理
private ICallback callback = new ICallback.Stub() {
@Override
public void onTaskStarted(int taskId) throws RemoteException {
runOnUiThread(() -> updateStatus("Task " + taskId + " started"));
}
@Override
public void onTaskProgress(int taskId, int progress) throws RemoteException {
runOnUiThread(() -> updateStatus("Task " + taskId + " progress: " + progress + "%"));
}
@Override
public void onTaskCompleted(int taskId, String result) throws RemoteException {
runOnUiThread(() -> updateStatus("Task " + taskId + " completed: " + result));
}
};
private void testCallbackService() {
if (callbackService != null) {
try {
callbackService.registerCallback(callback);
callbackService.startTask(1);
} catch (RemoteException e) {
Log.e(TAG, "Callback test failed", e);
}
}
}
5. Binder 传输数据类型
5.1 支持的数据类型
| 类型 | 说明 | 示例 |
|---|---|---|
| 基本类型 | int, long, float, double, boolean | int count = 10 |
| String | 字符串 | String name = "Android" |
| CharSequence | 字符序列 | CharSequence text |
| Parcelable | 可序列化对象 | DataModel data |
| List | 列表 | List<String> names |
| Map | 映射 | Map<String, Integer> scores |
5.2 复杂数据模型示例
java
// UserModel.java
public class UserModel implements Parcelable {
public int userId;
public String userName;
public List<String> permissions;
public Map<String, String> attributes;
// Parcelable 实现...
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(userId);
dest.writeString(userName);
dest.writeStringList(permissions);
dest.writeMap(attributes);
}
protected UserModel(Parcel in) {
userId = in.readInt();
userName = in.readString();
permissions = in.createStringArrayList();
attributes = in.readHashMap(String.class.getClassLoader());
}
}
6. Binder 最佳实践
6.1 性能优化
- 减少跨进程调用:批量处理数据,避免频繁的小数据调用
- 使用合适的参数方向 :
in: 客户端到服务端out: 服务端到客户端inout: 双向传输
6.2 错误处理
java
try {
String result = remoteService.doSomething(param);
// 处理结果
} catch (RemoteException e) {
// 处理通信错误
Log.e(TAG, "Remote call failed", e);
// 重连或提示用户
} catch (SecurityException e) {
// 处理权限错误
Log.e(TAG, "Permission denied", e);
}
6.3 内存管理
java
// 及时注销回调,避免内存泄漏
@Override
protected void onDestroy() {
if (isBound && callbackService != null) {
try {
callbackService.unregisterCallback(callback);
} catch (RemoteException e) {
// 忽略注销时的错误
}
}
unbindService(connection);
super.onDestroy();
}
7. 总结
通过以上实例,你应该掌握了:
- Binder 基础架构:理解 C/S 模式和 Binder Driver 的作用
- AIDL 使用:学会定义接口和数据模型
- 服务实现:创建 Binder 服务并处理客户端请求
- 客户端编程:绑定服务、调用远程方法、处理回调
- 数据传输:使用 Parcelable 传输复杂数据
- 错误处理:妥善处理 RemoteException 等异常
Binder 是 Android 系统的核心 IPC 机制,熟练掌握 Binder 对于开发系统服务、跨进程通信等高级功能至关重要。