AIDL简单使用
一、AIDL基础
AIDL(Android Interface Definition Language) 是Android用于跨进程通信的接口定义语言,基于Binder机制实现。
核心流程:
- 定义接口(.aidl文件)
- 实现接口(服务端)
- 绑定服务(客户端)
- 跨进程调用
二、Demo
- 定义AIDL接口
文件:ICalculator.aidl
// ICalculator.aidl
package com.example.aidldemo; interface ICalculator { int add(int a, int b); int subtract(int a, int b);
}
- 实现服务端
CalculatorService.kt
class CalculatorService : Service() { private val binder = object : ICalculator.Stub() { override fun add(a: Int, b: Int): Int = a + b override fun subtract(a: Int, b: Int): Int = a - b } override fun onBind(intent: Intent): IBinder = binder
}
AndroidManifest.xml
<service android:name=".CalculatorService" android:exported="true" android:process=":remote"/>
客户端绑定与调用
MainActivity.kt
class MainActivity : AppCompatActivity() { private var calculator: ICalculator? = null private val connection = object : ServiceConnection { override fun onServiceConnected(name: ComponentName?, service: IBinder?) { calculator = ICalculator.Stub.asInterface(service) } override fun onServiceDisconnected(name: ComponentName?) { calculator = null } } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) bindService( Intent(this, CalculatorService::class.java), connection, Context.BIND_AUTO_CREATE ) // 调用示例 btnAdd.setOnClickListener { val result = calculator?.add(5, 3) // 输出8 Toast.makeText(this, "Result: $result", Toast.LENGTH_SHORT).show() } } override fun onDestroy() { unbindService(connection) super.onDestroy() }
}
三、传递自定义对象
- 定义Parcelable对象
User.kt
@Parcelize
data class User(val id: Int, val name: String) : Parcelable
IUserManager.aidl
// IUserManager.aidl
package com.example.aidldemo;
import com.example.aidldemo.User; interface IUserManager { void addUser(in User user); List<User> getUsers();
}
- 实现服务端
UserManagerService.kt
class UserManagerService : Service() { private val users = mutableListOf<User>() private val binder = object : IUserManager.Stub() { override fun addUser(user: User) { users.add(user) } override fun getUsers(): MutableList<User> = users } override fun onBind(intent: Intent): IBinder = binder
}
- 客户端调用
val userManager = IUserManager.Stub.asInterface(service)
userManager.addUser(User(1, "Alice"))
val userList = userManager.users // 获取用户列表
四、关键问题与解决方案
-
线程模型
- 服务端方法默认运行在Binder线程池
- 解决方案:
override fun addUser(user: User) { // 切换到主线程更新UI Handler(Looper.getMainLooper()).post { // 更新UI操作 } }
-
异常处理
try { val result = calculator?.add(5, 3)
} catch (e: RemoteException) { Log.e("AIDL", "Remote call failed", e)
}
- 权限控制
服务端验证权限:
override fun onTransact(code: Int, data: Parcel, reply: Parcel?, flags: Int): Boolean { val permission = checkCallingOrSelfPermission("com.example.PERMISSION") if (permission != PackageManager.PERMISSION_GRANTED) { throw SecurityException("Permission denied") } return super.onTransact(code, data, reply, flags)
}
五、性能优化技巧
批量数据传输:
// AIDL接口定义
void addUsers(in List<User> users);
使用oneway非阻塞调用:
oneway void logEvent(in String event);
对象池复用:
private val userPool = Pools.SynchronizedPool<User>(10) fun getUser(): User = userPool.acquire() ?: User()
fun recycleUser(user: User) = userPool.release(user)
服务端断连处理
服务断开 → onServiceDisconnected/binderDied → 启动重连 → 指数退避重试
├─ 成功 → 重置重试计数
└─ 失败 → 提示用户
- 检测服务端断连
通过 ServiceConnection 监听连接状态
private val serviceConnection = object : ServiceConnection {override fun onServiceConnected(name: ComponentName?, service: IBinder?) {// 绑定成功aidlService = IMyAidlInterface.Stub.asInterface(service)// 添加死亡监听(关键!)service?.linkToDeath(deathRecipient, 0)}override fun onServiceDisconnected(name: ComponentName?) {// 服务异常断开aidlService = nullscheduleReconnect() // 触发重连逻辑}
}// Binder 死亡监听(更底层)
private val deathRecipient = IBinder.DeathRecipient {runOnUiThread {Toast.makeText(this, "服务端进程终止,尝试重连...", Toast.LENGTH_SHORT).show()scheduleReconnect()}
}
通过 linkToDeath 监听 Binder 死亡
//更底层监听 Binder 对象存活状态:
private fun registerBinderDeathListener(binder: IBinder?) {binder?.linkToDeath(object : IBinder.DeathRecipient {override fun binderDied() {// Binder死亡(非主线程,需切线程处理)runOnUiThread {showToast("服务已断开,正在重连...")scheduleReconnect()}}}, 0) // flags 传0即可
}
- 自动重连策略
指数退避重连
private var reconnectAttempts = 0
private val maxReconnectAttempts = 5
private val reconnectHandler = Handler(Looper.getMainLooper())private fun scheduleReconnect() {if (reconnectAttempts >= maxReconnectAttempts) {Log.w("AIDL", "超过最大重试次数,放弃重连")return}val delay = 2_000L * (reconnectAttempts + 1) // 2s, 4s, 8s...reconnectHandler.postDelayed({bindAidlService()reconnectAttempts++}, delay)
}private fun bindService() {val intent = Intent(this, CalculatorService::class.java)bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE)
}