AIDL学习

目录

一、项目准备

1. 创建主项目(服务端 + 客户端可在同一项目,也可分开,这里以单项目多模块为例)

二、创建 AIDL 接口文件(核心步骤)

1. 创建 AIDL 目录和文件

2. 编写 AIDL 接口内容

3. 同步 AIDL 文件

三、实现服务端 Service

1. 创建 Service 类

2. 在 Manifest 中注册 Service(关键:指定独立进程)

四、编写客户端 Activity(绑定服务并通信)

1. 创建布局文件

2. 编写客户端 Activity 代码

五、运行与验证

1. 运行项目

2. 操作流程与预期效果

六、核心流程总结

文件路径总览

项目结构与文件作用

代码执行流程(时序图)

核心流程拆解(分阶段详解)

阶段 1:AIDL 接口定义与生成

阶段 2:服务端 Service 实现

阶段 3:客户端绑定服务(跨进程连接建立)

阶段 4:跨进程方法调用(核心交互)

阶段 5:服务销毁(可选)

跨进程通信原理(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 方法

六、核心流程总结

  1. AIDL 接口定义:通过 .aidl 文件声明跨进程方法,系统自动生成 Java 接口(含 Stub 内部类)。
  2. 服务端实现Service 中创建 Stub 子类,实现 AIDL 方法,通过 onBind 返回 IBinder
  3. 客户端绑定:通过 bindService 绑定服务,在 onServiceConnected 中通过 Stub.asInterface 获取 AIDL 接口实例。
  4. 跨进程通信:客户端调用 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.aidlAIDL 接口定义跨进程通信的方法(如 addgetServiceInfo),是通信 “协议”
app/src/main/java/com/example/aidldemo/MyAidlService.javaService服务端实现,通过 Stub 子类实现 AIDL 方法,供客户端绑定
app/src/main/java/com/example/aidldemo/MainActivity.javaActivity客户端界面,负责绑定服务、调用 AIDL 方法
app/src/main/AndroidManifest.xml清单文件注册 MyAidlService,并指定独立进程(模拟跨进程)
app/src/main/res/layout/activity_main.xml布局文件客户端 UI,包含绑定、调用按钮和结果显示文本

代码执行流程(时序图)

从 应用启动 → 绑定服务 → 跨进程调用 → 服务销毁 ,完整时序如下:

核心流程拆解(分阶段详解)

阶段 1:AIDL 接口定义与生成

  1. 编写 AIDL 文件
    在 IMyAidlInterface.aidl 中声明跨进程方法(addgetServiceInfo),这是通信的 “契约”。
  2. 自动生成 Java 接口
    执行 Make Project 后,系统自动生成 IMyAidlInterface.java ,包含:
    • Stub 抽象类(服务端需继承实现,客户端通过它获取接口实例)。
    • asInterface(IBinder) 方法(客户端用它将 IBinder 转换为 AIDL 接口)。

阶段 2:服务端 Service 实现

  1. 继承 Stub 并实现方法
    MyAidlService 中创建 Stub 子类,重写 add 和 getServiceInfo 方法,实现业务逻辑。
  2. 通过 onBind 返回 IBinder
    客户端绑定服务时,onBind 返回 Stub 的 IBinder,作为跨进程通信的 “通道”。

阶段 3:客户端绑定服务(跨进程连接建立)

  1. 发起绑定请求
    客户端调用 bindService,传入 Intent(指定 Service 的 Action 和包名)。
  2. 系统启动 Service
    若 Service 未启动,系统先调用 MyAidlService.onCreate() 创建服务。
  3. 返回 IBinder 并建立连接
    服务端 onBind 返回 Stub 的 IBinder,系统通过 Binder 机制传递给客户端。
  4. 客户端获取 AIDL 接口实例
    客户端在 onServiceConnected 中,通过 Stub.asInterface(IBinder) 获取 AIDL 接口实例,后续可直接调用接口方法。

阶段 4:跨进程方法调用(核心交互)

以 add(100, 200) 为例,跨进程调用流程:

  1. 客户端调用 AIDL 方法
    mAidlInterface.add(100, 200) 触发跨进程调用。
  2. Binder 机制传输参数
    系统将参数(100, 200)通过 Binder 驱动,从客户端进程传输到服务端进程。
  3. 服务端执行逻辑并返回结果
    服务端 Stub 的 add 方法被调用,计算结果(300)后,再通过 Binder 机制传回客户端。
  4. 客户端接收结果并更新 UI
    客户端拿到结果(300),更新文本框显示。

阶段 5:服务销毁(可选)

  • 手动解绑:客户端 onDestroy 中调用 unbindService,触发服务端 onUnbind(若不再有其他绑定,会调用 onDestroy 销毁 Service)。
  • 系统回收:若 Service 是 startService 启动的,需手动 stopService 或 stopSelf 销毁。

跨进程通信原理(Binder 机制)

AIDL 底层依赖 Android Binder 机制 实现跨进程通信,核心流程:

  1. 进程隔离:Android 中不同应用 / 模块运行在独立进程,内存不共享。
  2. Binder 驱动:作为进程间通信的 “桥梁”,负责传递数据、转发调用。
  3. Proxy/Stub 代理
    • 客户端通过 Stub.asInterface 获取 Proxy 代理,调用方法时,Proxy 将参数打包,通过 Binder 发送给服务端。
    • 服务端 Stub 接收请求,解包参数并执行实际方法,再将结果打包返回。

关键细节与注意事项

  1. AIDL 数据类型限制
    仅支持基本类型、StringParcelableList(元素需是 AIDL 支持类型)、Map(键值需是 AIDL 支持类型)。
  2. 进程安全
    服务端 Stub 的方法运行在服务端进程,需注意线程安全(默认在主线程,耗时操作需开线程)。
  3. 绑定状态管理
    客户端需在 onDestroy 中解绑服务,避免内存泄漏。
  4. 异常处理
    跨进程调用可能因服务端崩溃、进程被杀等失败,需捕获 RemoteException
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值