目录
[1. 创建主项目(服务端 + 客户端可在同一项目,也可分开,这里以单项目多模块为例)](#1. 创建主项目(服务端 + 客户端可在同一项目,也可分开,这里以单项目多模块为例))
[二、创建 AIDL 接口文件(核心步骤)](#二、创建 AIDL 接口文件(核心步骤))
[1. 创建 AIDL 目录和文件](#1. 创建 AIDL 目录和文件)
[2. 编写 AIDL 接口内容](#2. 编写 AIDL 接口内容)
[3. 同步 AIDL 文件](#3. 同步 AIDL 文件)
[三、实现服务端 Service](#三、实现服务端 Service)
[1. 创建 Service 类](#1. 创建 Service 类)
[2. 在 Manifest 中注册 Service(关键:指定独立进程)](#2. 在 Manifest 中注册 Service(关键:指定独立进程))
[四、编写客户端 Activity(绑定服务并通信)](#四、编写客户端 Activity(绑定服务并通信))
[1. 创建布局文件](#1. 创建布局文件)
[2. 编写客户端 Activity 代码](#2. 编写客户端 Activity 代码)
[1. 运行项目](#1. 运行项目)
[2. 操作流程与预期效果](#2. 操作流程与预期效果)
[阶段 1:AIDL 接口定义与生成](#阶段 1:AIDL 接口定义与生成)
[阶段 2:服务端 Service 实现](#阶段 2:服务端 Service 实现)
[阶段 3:客户端绑定服务(跨进程连接建立)](#阶段 3:客户端绑定服务(跨进程连接建立))
[阶段 4:跨进程方法调用(核心交互)](#阶段 4:跨进程方法调用(核心交互))
[阶段 5:服务销毁(可选)](#阶段 5:服务销毁(可选))
[跨进程通信原理(Binder 机制)](#跨进程通信原理(Binder 机制))
一、项目准备
1. 创建主项目(服务端 + 客户端可在同一项目,也可分开,这里以单项目多模块为例)
- 打开 Android Studio,新建 Empty Activity 项目,命名为
AIDLDemo
,包名默认com.example.aidldemo
,语言选 Java。 - 项目结构采用 单应用内跨进程(通过不同进程启动服务),无需创建多模块。
二、创建 AIDL 接口文件(核心步骤)
AIDL 文件是跨进程通信的 "协议",服务端和客户端需完全一致(包名、内容)。
1. 创建 AIDL 目录和文件
- 路径 :在
app/src/main
目录右键 →New
→Folder
→AIDL Folder
,默认路径即可(自动生成aidl
目录)。 - 在
aidl
目录下创建与 Java 代码相同的包名(保持包结构一致):
右键aidl
→New
→Package
,输入com.example.aidldemo
。 - 在该包下创建 AIDL 接口文件:
右键包名 →New
→AIDL File
,命名为IMyAidlInterface.aidl
。
2. 编写 AIDL 接口内容
文件路径 :app/src/main/aidl/com/example/aidldemo/IMyAidlInterface.aidl
// IMyAidlInterface.aidl
package com.example.aidldemo;
// 定义跨进程调用的接口方法
interface IMyAidlInterface {
// 示例:加法计算
int add(int a, int b);
// 示例:获取服务端信息
String getServiceInfo();
}
3. 同步 AIDL 文件
点击菜单栏 Build → Make Project ,系统会自动在 app/build/generated/aidl_source_output_dir
目录生成对应的 Java 接口文件(无需手动修改)。
三、实现服务端 Service
服务端需创建 Service
并实现 AIDL 接口,通过 onBind
返回接口实例。
1. 创建 Service 类
文件路径 :app/src/main/java/com/example/aidldemo/MyAidlService.java
package com.example.aidldemo;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
// 服务端 Service,实现 AIDL 接口
public class MyAidlService extends Service {
private static final String TAG = "MyAidlService";
// 创建 AIDL 接口的实现类(Stub 是自动生成的抽象类)
private final IMyAidlInterface.Stub mBinder = new IMyAidlInterface.Stub() {
@Override
public int add(int a, int b) throws RemoteException {
Log.d(TAG, "客户端调用 add 方法:a=" + a + ", b=" + b);
return a + b; // 实现加法逻辑
}
@Override
public String getServiceInfo() throws RemoteException {
Log.d(TAG, "客户端调用 getServiceInfo 方法");
return "这是来自服务端的消息:AIDL 通信成功!";
}
};
@Override
public void onCreate() {
super.onCreate();
Log.d(TAG, "Service 已创建");
}
// 返回 AIDL 接口实例,供客户端绑定
@Override
public IBinder onBind(Intent intent) {
Log.d(TAG, "客户端绑定服务");
return mBinder;
}
@Override
public void onDestroy() {
super.onDestroy();
Log.d(TAG, "Service 已销毁");
}
}
2. 在 Manifest 中注册 Service(关键:指定独立进程)
文件路径 :app/src/main/AndroidManifest.xml
在 <application>
标签内添加 Service 声明,并通过 android:process
指定独立进程(模拟跨进程场景):
<service
android:name=".MyAidlService"
android:enabled="true"
android:exported="true"
android:process=":remote"> <!-- 关键:指定独立进程,名称任意,以冒号开头表示私有进程 -->
<intent-filter>
<action android:name="com.example.aidldemo.AIDL_SERVICE" /> <!-- 自定义 Action,供客户端绑定 -->
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</service>
四、编写客户端 Activity(绑定服务并通信)
客户端需绑定服务端 Service,通过 AIDL 接口调用服务端方法。
1. 创建布局文件
文件路径 :app/src/main/res/layout/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="20dp"
android:gravity="center_horizontal">
<Button
android:id="@+id/btn_bind"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="绑定服务" />
<Button
android:id="@+id/btn_add"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="调用加法方法"
android:layout_marginTop="20dp" />
<Button
android:id="@+id/btn_get_info"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="获取服务信息"
android:layout_marginTop="20dp" />
<TextView
android:id="@+id/tv_result"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:textSize="16sp" />
</LinearLayout>
2. 编写客户端 Activity 代码
文件路径 :app/src/main/java/com/example/aidldemo/MainActivity.java
package com.example.aidldemo;
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 android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
// 客户端 Activity,绑定服务并通过 AIDL 通信
public class MainActivity extends AppCompatActivity {
private static final String TAG = "MainActivity";
private IMyAidlInterface mAidlInterface; // AIDL 接口实例
private boolean isBound = false; // 服务是否已绑定
private TextView tvResult;
// 服务连接回调,监控绑定状态
private ServiceConnection mServiceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
// 绑定成功:通过 IBinder 获取 AIDL 接口实例
mAidlInterface = IMyAidlInterface.Stub.asInterface(service);
isBound = true;
Log.d(TAG, "服务绑定成功");
tvResult.setText("服务绑定成功,可调用方法");
}
@Override
public void onServiceDisconnected(ComponentName name) {
// 服务意外断开(如崩溃)
mAidlInterface = null;
isBound = false;
Log.d(TAG, "服务断开连接");
tvResult.setText("服务已断开");
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tvResult = findViewById(R.id.tv_result);
// 绑定服务按钮
findViewById(R.id.btn_bind).setOnClickListener(v -> bindToService());
// 调用加法方法按钮
findViewById(R.id.btn_add).setOnClickListener(v -> callAddMethod());
// 获取服务信息按钮
findViewById(R.id.btn_get_info).setOnClickListener(v -> callGetInfoMethod());
}
// 绑定服务端 Service
private void bindToService() {
if (isBound) {
Toast.makeText(this, "服务已绑定", Toast.LENGTH_SHORT).show();
return;
}
Intent intent = new Intent();
intent.setAction("com.example.aidldemo.AIDL_SERVICE"); // 与 Manifest 中声明的 Action 一致
intent.setPackage(getPackageName()); // 指定服务端包名(当前应用包名)
// 绑定服务:BIND_AUTO_CREATE 表示若服务未启动则自动创建
bindService(intent, mServiceConnection, BIND_AUTO_CREATE);
}
// 调用服务端的 add 方法
private void callAddMethod() {
if (!isBound || mAidlInterface == null) {
Toast.makeText(this, "请先绑定服务", Toast.LENGTH_SHORT).show();
return;
}
try {
int result = mAidlInterface.add(100, 200); // 跨进程调用加法
String text = "100 + 200 = " + result;
tvResult.setText(text);
Log.d(TAG, text);
} catch (RemoteException e) {
e.printStackTrace();
tvResult.setText("调用 add 方法失败:" + e.getMessage());
}
}
// 调用服务端的 getServiceInfo 方法
private void callGetInfoMethod() {
if (!isBound || mAidlInterface == null) {
Toast.makeText(this, "请先绑定服务", Toast.LENGTH_SHORT).show();
return;
}
try {
String info = mAidlInterface.getServiceInfo(); // 跨进程调用获取信息
tvResult.setText(info);
Log.d(TAG, "服务信息:" + info);
} catch (RemoteException e) {
e.printStackTrace();
tvResult.setText("调用 getServiceInfo 方法失败:" + e.getMessage());
}
}
@Override
protected void onDestroy() {
super.onDestroy();
// 解绑服务,避免内存泄漏
if (isBound) {
unbindService(mServiceConnection);
isBound = false;
Log.d(TAG, "服务已解绑");
}
}
}
五、运行与验证
1. 运行项目
点击 Android Studio 运行按钮,将应用安装到模拟器或真机。
2. 操作流程与预期效果
步骤 | 操作 | 预期结果 |
---|---|---|
1 | 点击 绑定服务 | 日志显示 服务绑定成功 ,文本框显示 "服务绑定成功,可调用方法" |
2 | 点击 调用加法方法 | 文本框显示 100 + 200 = 300 ,服务端日志显示 客户端调用 add 方法 |
3 | 点击 获取服务信息 | 文本框显示 这是来自服务端的消息:AIDL 通信成功! ,服务端日志显示 客户端调用 getServiceInfo 方法 |
六、核心流程总结
- AIDL 接口定义 :通过
.aidl
文件声明跨进程方法,系统自动生成 Java 接口(含Stub
内部类)。 - 服务端实现 :
Service
中创建Stub
子类,实现 AIDL 方法,通过onBind
返回IBinder
。 - 客户端绑定 :通过
bindService
绑定服务,在onServiceConnected
中通过Stub.asInterface
获取 AIDL 接口实例。 - 跨进程通信:客户端调用 AIDL 接口方法,底层通过 Binder 机制实现进程间数据传输,服务端处理后返回结果。
文件路径总览
app
└── src
└── main
├── aidl
│ └── com
│ └── example
│ └── aidldemo
│ └── IMyAidlInterface.aidl // AIDL 接口文件
├── java
│ └── com
│ └── example
│ └── aidldemo
│ ├── MainActivity.java // 客户端 Activity
│ └── MyAidlService.java // 服务端 Service
├── AndroidManifest.xml // 注册 Service 并指定进程
└── res
└── layout
└── activity_main.xml // 客户端布局
项目结构与文件作用
先理清项目关键文件的职责,后续流程会围绕这些文件展开:
文件路径 | 类型 | 作用 |
---|---|---|
app/src/main/aidl/com/example/aidldemo/IMyAidlInterface.aidl |
AIDL 接口 | 定义跨进程通信的方法(如 add 、getServiceInfo ),是通信 "协议" |
app/src/main/java/com/example/aidldemo/MyAidlService.java |
Service | 服务端实现,通过 Stub 子类实现 AIDL 方法,供客户端绑定 |
app/src/main/java/com/example/aidldemo/MainActivity.java |
Activity | 客户端界面,负责绑定服务、调用 AIDL 方法 |
app/src/main/AndroidManifest.xml |
清单文件 | 注册 MyAidlService ,并指定独立进程(模拟跨进程) |
app/src/main/res/layout/activity_main.xml |
布局文件 | 客户端 UI,包含绑定、调用按钮和结果显示文本 |
代码执行流程(时序图)
从 应用启动 → 绑定服务 → 跨进程调用 → 服务销毁 ,完整时序如下:

核心流程拆解(分阶段详解)
阶段 1:AIDL 接口定义与生成
- 编写 AIDL 文件 :
在IMyAidlInterface.aidl
中声明跨进程方法(add
、getServiceInfo
),这是通信的 "契约"。 - 自动生成 Java 接口 :
执行Make Project
后,系统自动生成IMyAidlInterface.java
,包含:Stub
抽象类(服务端需继承实现,客户端通过它获取接口实例)。asInterface(IBinder)
方法(客户端用它将IBinder
转换为 AIDL 接口)。
阶段 2:服务端 Service 实现
- 继承
Stub
并实现方法 :
MyAidlService
中创建Stub
子类,重写add
和getServiceInfo
方法,实现业务逻辑。 - 通过
onBind
返回IBinder
:
客户端绑定服务时,onBind
返回Stub
的IBinder
,作为跨进程通信的 "通道"。
阶段 3:客户端绑定服务(跨进程连接建立)
- 发起绑定请求 :
客户端调用bindService
,传入Intent
(指定 Service 的 Action 和包名)。 - 系统启动 Service :
若 Service 未启动,系统先调用MyAidlService.onCreate()
创建服务。 - 返回
IBinder
并建立连接 :
服务端onBind
返回Stub
的IBinder
,系统通过 Binder 机制传递给客户端。 - 客户端获取 AIDL 接口实例 :
客户端在onServiceConnected
中,通过Stub.asInterface(IBinder)
获取 AIDL 接口实例,后续可直接调用接口方法。
阶段 4:跨进程方法调用(核心交互)
以 add(100, 200)
为例,跨进程调用流程:
- 客户端调用 AIDL 方法 :
mAidlInterface.add(100, 200)
触发跨进程调用。 - Binder 机制传输参数 :
系统将参数(100, 200)通过 Binder 驱动,从客户端进程传输到服务端进程。 - 服务端执行逻辑并返回结果 :
服务端Stub
的add
方法被调用,计算结果(300)后,再通过 Binder 机制传回客户端。 - 客户端接收结果并更新 UI :
客户端拿到结果(300),更新文本框显示。
阶段 5:服务销毁(可选)
- 手动解绑 :客户端
onDestroy
中调用unbindService
,触发服务端onUnbind
(若不再有其他绑定,会调用onDestroy
销毁 Service)。 - 系统回收 :若 Service 是
startService
启动的,需手动stopService
或stopSelf
销毁。
跨进程通信原理(Binder 机制)
AIDL 底层依赖 Android Binder 机制 实现跨进程通信,核心流程:
- 进程隔离:Android 中不同应用 / 模块运行在独立进程,内存不共享。
- Binder 驱动:作为进程间通信的 "桥梁",负责传递数据、转发调用。
- Proxy/Stub 代理 :
- 客户端通过
Stub.asInterface
获取Proxy
代理,调用方法时,Proxy
将参数打包,通过 Binder 发送给服务端。 - 服务端
Stub
接收请求,解包参数并执行实际方法,再将结果打包返回。
- 客户端通过
关键细节与注意事项
- AIDL 数据类型限制 :
仅支持基本类型、String
、Parcelable
、List
(元素需是 AIDL 支持类型)、Map
(键值需是 AIDL 支持类型)。 - 进程安全 :
服务端Stub
的方法运行在服务端进程,需注意线程安全(默认在主线程,耗时操作需开线程)。 - 绑定状态管理 :
客户端需在onDestroy
中解绑服务,避免内存泄漏。 - 异常处理 :
跨进程调用可能因服务端崩溃、进程被杀等失败,需捕获RemoteException
。