Android Binder 詳解與實(shí)踐指南(最新推薦)
Android Binder 詳解與實(shí)踐指南
1. Binder 基礎(chǔ)概念
1.1 什么是 Binder?
Binder 是 Android 系統(tǒng)中最重要的進(jìn)程間通信(IPC)機(jī)制,它具有以下特點(diǎn):
- 高性能:相比其他 IPC 機(jī)制,Binder 只需要一次數(shù)據(jù)拷貝
- 安全性:基于 C/S 架構(gòu),支持身份驗(yàn)證
- 面向?qū)ο?/strong>:可以像調(diào)用本地方法一樣調(diào)用遠(yuǎn)程方法
1.2 Binder 架構(gòu)組件
Client Process → Binder Driver → Server Process
↓ ↓
Binder Proxy Binder Object2. Binder 基礎(chǔ)實(shí)例
2.1 簡(jiǎn)單的 Binder 服務(wù)端
// 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 接口的實(shí)現(xiàn)
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());
// 處理數(shù)據(jù)...
}
};
@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 接口
// ISimpleService.aidl
package com.example.binderdemo;
// 定義數(shù)據(jù)模型
parcelable DataModel;
interface ISimpleService {
int add(int a, int b);
String greet(String name);
void sendData(in DataModel data);
}2.3 數(shù)據(jù)模型定義
// 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 客戶(hù)端實(shí)現(xiàn)
// 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 {
// 測(cè)試加法
int result = simpleService.add(5, 3);
String message = "5 + 3 = " + result;
// 測(cè)試問(wèn)候
String greeting = simpleService.greet("Android Developer");
// 測(cè)試數(shù)據(jù)傳輸
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 布局文件
<!-- 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 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. 運(yùn)行結(jié)果分析
首次運(yùn)行應(yīng)用:
MainActivity: Status: Not connected
點(diǎn)擊 “Bind Service” 按鈕:
SimpleBinderService: Service created SimpleBinderService: onBind() called MainActivity: Service connected MainActivity: Status: Service Connected
點(diǎn)擊 “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}點(diǎn)擊 “Unbind Service” 按鈕:
SimpleBinderService: Service destroyed MainActivity: Service Unbound
4. 高級(jí) Binder 特性
4.1 帶回調(diào)的 Binder 服務(wù)
// 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 回調(diào)服務(wù)實(shí)現(xiàn)
// 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 {
// 通知任務(wù)開(kāi)始
for (ICallback callback : callbacks) {
callback.onTaskStarted(taskId);
}
// 模擬任務(wù)執(zhí)行
for (int i = 0; i <= 100; i += 10) {
Thread.sleep(200);
// 更新進(jìn)度
for (ICallback callback : callbacks) {
callback.onTaskProgress(taskId, i);
}
}
// 任務(wù)完成
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 客戶(hù)端回調(diào)處理
// 在 MainActivity 中添加回調(diào)處理
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 傳輸數(shù)據(jù)類(lèi)型
5.1 支持的數(shù)據(jù)類(lèi)型
| 類(lèi)型 | 說(shuō)明 | 示例 |
|---|---|---|
| 基本類(lèi)型 | int, long, float, double, boolean | int count = 10 |
| String | 字符串 | String name = "Android" |
| CharSequence | 字符序列 | CharSequence text |
| Parcelable | 可序列化對(duì)象 | DataModel data |
| List | 列表 | List<String> names |
| Map | 映射 | Map<String, Integer> scores |
5.2 復(fù)雜數(shù)據(jù)模型示例
// UserModel.java
public class UserModel implements Parcelable {
public int userId;
public String userName;
public List<String> permissions;
public Map<String, String> attributes;
// Parcelable 實(shí)現(xiàn)...
@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 最佳實(shí)踐
6.1 性能優(yōu)化
- 減少跨進(jìn)程調(diào)用:批量處理數(shù)據(jù),避免頻繁的小數(shù)據(jù)調(diào)用
- 使用合適的參數(shù)方向:
in: 客戶(hù)端到服務(wù)端out: 服務(wù)端到客戶(hù)端inout: 雙向傳輸
6.2 錯(cuò)誤處理
try {
String result = remoteService.doSomething(param);
// 處理結(jié)果
} catch (RemoteException e) {
// 處理通信錯(cuò)誤
Log.e(TAG, "Remote call failed", e);
// 重連或提示用戶(hù)
} catch (SecurityException e) {
// 處理權(quán)限錯(cuò)誤
Log.e(TAG, "Permission denied", e);
}6.3 內(nèi)存管理
// 及時(shí)注銷(xiāo)回調(diào),避免內(nèi)存泄漏
@Override
protected void onDestroy() {
if (isBound && callbackService != null) {
try {
callbackService.unregisterCallback(callback);
} catch (RemoteException e) {
// 忽略注銷(xiāo)時(shí)的錯(cuò)誤
}
}
unbindService(connection);
super.onDestroy();
}7. 總結(jié)
通過(guò)以上實(shí)例,你應(yīng)該掌握了:
- Binder 基礎(chǔ)架構(gòu):理解 C/S 模式和 Binder Driver 的作用
- AIDL 使用:學(xué)會(huì)定義接口和數(shù)據(jù)模型
- 服務(wù)實(shí)現(xiàn):創(chuàng)建 Binder 服務(wù)并處理客戶(hù)端請(qǐng)求
- 客戶(hù)端編程:綁定服務(wù)、調(diào)用遠(yuǎn)程方法、處理回調(diào)
- 數(shù)據(jù)傳輸:使用 Parcelable 傳輸復(fù)雜數(shù)據(jù)
- 錯(cuò)誤處理:妥善處理 RemoteException 等異常
Binder 是 Android 系統(tǒng)的核心 IPC 機(jī)制,熟練掌握 Binder 對(duì)于開(kāi)發(fā)系統(tǒng)服務(wù)、跨進(jìn)程通信等高級(jí)功能至關(guān)重要。
到此這篇關(guān)于Android Binder 詳解與實(shí)踐指南的文章就介紹到這了,更多相關(guān)Android Binder內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Kotlin Compose Button 實(shí)現(xiàn)長(zhǎng)按監(jiān)聽(tīng)并實(shí)現(xiàn)動(dòng)畫(huà)效果(完整代碼)
想要實(shí)現(xiàn)長(zhǎng)按按鈕開(kāi)始錄音,松開(kāi)發(fā)送的功能,因此為了實(shí)現(xiàn)這些功能就需要自己寫(xiě)一個(gè) Button 來(lái)解決問(wèn)題,下面小編給大家分享Kotlin Compose Button 實(shí)現(xiàn)長(zhǎng)按監(jiān)聽(tīng)并實(shí)現(xiàn)動(dòng)畫(huà)效果(完整代碼),感興趣的朋友一起看看吧2025-05-05
Android Studio 通過(guò)登錄功能介紹SQLite數(shù)據(jù)庫(kù)的使用流程
SQLite是一款輕型的數(shù)據(jù)庫(kù),是遵守ACID的關(guān)系型數(shù)據(jù)庫(kù)管理系統(tǒng),它包含在一個(gè)相對(duì)小的C庫(kù)中。這篇文章主要介紹了Android Studio 通過(guò)登錄功能介紹SQLite數(shù)據(jù)庫(kù)的使用流程,需要的朋友可以參考下2018-09-09
RecyclerView+CardView實(shí)現(xiàn)橫向卡片式滑動(dòng)效果
這篇文章主要為大家詳細(xì)介紹了RecyclerView+CardView實(shí)現(xiàn)橫向卡片式滑動(dòng)效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-01-01
Android編程實(shí)現(xiàn)自定義輸入法功能示例【輸入密碼時(shí)防止第三方竊取】
這篇文章主要介紹了Android編程實(shí)現(xiàn)自定義輸入法功能,可實(shí)習(xí)輸入密碼時(shí)防止第三方竊取的效果,結(jié)合實(shí)例形式詳細(xì)分析了Android布局、控件及輸入法相關(guān)操作技巧,需要的朋友可以參考下2017-01-01
Android編程實(shí)現(xiàn)獲取圖片資源的四種方法
這篇文章主要介紹了Android編程實(shí)現(xiàn)獲取圖片資源的四種方法,分別針對(duì)圖片所在目錄位置分析了Android獲取圖片資源的相關(guān)技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-11-11
Android ContentProvider的實(shí)現(xiàn)及簡(jiǎn)單實(shí)例代碼
這篇文章主要介紹了Android ContentProvider的實(shí)現(xiàn)及簡(jiǎn)單實(shí)例代碼的相關(guān)資料,需要的朋友可以參考下2017-02-02

