IPC方式

33 阅读8分钟

一. Messenger

  1. 要确保服务端进程处于存活状态,可以使用bindService拉起服务端进程

  2. 客户端binder对象传递到服务端,可通过service或者跳转参数携带(如Intent)

  3. 服务端给客户端发送消息,服务端拿到客户端binder后,创建一个客户端binder的Messenger对象,就可以给客户端发送消息

  4. 实现服务端的MessengerHandler

  5. 客户端给服务端发送消息,创建一个服务端的Messenger,通过Message中的replyTo给客户端

  6. 实现客户端MessengerHandler

public class MessengerService extends Service {
    private static final String TAG = "MessagerService";

    /**
     * 处理来自客户端的消息,并用于构建Messenger
     */
    private static class MessengerHandler extends Handler {
        @Override
        public void handleMessage(Message message) {
            switch (message.what) {
                case Constant.MESSAGE_FROM_CLIENT:
                    Log.e(TAG, "receive message from client:" + message.getData().getString("msg"));
                    //获取客户端传递过来的Messenger,通过这个Messenger回传消息给客户端
                    Messenger client = message.replyTo;
                    //当然,回传消息还是要通过message
                    Message msg = Message.obtain(null, Constant.MESSAGE_FROM_SERVICE);
                    Bundle bundle = new Bundle();
                    bundle.putString("msg", "hello client, I have received your message!");
                    msg.setData(bundle);
                    try {
                        client.send(msg);
                    } catch (RemoteException e) {
                        e.printStackTrace();
                    }
                    break;
                default:
                    super.handleMessage(message);
                    break;
            }
        }
    }

    /**
     * 构建Messenger对象
     */
    private final Messenger mMessenger = new Messenger(new MessengerHandler());

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        //将Messenger对象的Binder返回给客户端
        return mMessenger.getBinder();
    }
}


/**
 * 客户端Messenger对象
 */
private Messenger mClientMessenger = new Messenger(new MessengerHandler());

private ServiceConnection mConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
            Log.e(TAG, "ServiceConnection-->" + System.currentTimeMillis());
            mService = new Messenger(iBinder);
            Message message = Message.obtain(null, MESSAGE_FROM_CLIENT);
            Bundle bundle = new Bundle();
            bundle.putString("msg", "hello service,this is client");
            message.setData(bundle);
            //将客户端的Messenger对象传递给服务端
            message.replyTo = mClientMessenger;
            try {
                mService.send(message);
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }

        @Override
        public void onServiceDisconnected(ComponentName componentName) {
            Log.e(TAG, "onServiceDisconnected-->binder died");
        }
    };
    
/**
 * 用于构建客户端的Messenger对象,并处理服务端的消息
 */
private static class MessengerHandler extends Handler {
    @Override
    public void handleMessage(Message message) {
        switch (message.what) {
            case Constant.MESSAGE_FROM_SERVICE:
                Log.e(TAG, "receive message from service:" + message.getData().getString("msg"));
                break;
            default:
                super.handleMessage(message);
                break;
        }
    }
}    

二. AIDL

  1. 创建 AIDL 接口文件

首先在 src/main/aidl/com/example/service/ 目录下创建 IUserManager.aidl:

// IUserManager.aidl
package com.example.service;

// 定义用户数据类
parcelable UserData;

interface IUserManager {
    // 添加用户
    int addUser(in UserData user);
    
    // 删除用户
    boolean deleteUser(int userId);
    
    // 获取用户列表
    List<UserData> getUserList();
    
    // 获取用户数量
    int getUserCount();
    
    // 注册回调监听器
    void registerListener(IUserCallback callback);
    
    // 注销回调监听器
    void unregisterListener(IUserCallback callback);
}

在相同目录下创建 IUserCallback.aidl:

// IUserCallback.aidl
package com.example.service;

interface IUserCallback {
    // 用户添加回调
    void onUserAdded(in UserData user);
    
    // 用户删除回调
    void onUserDeleted(int userId);
    
    // 用户数量变化回调
    void onUserCountChanged(int count);
}

在相同目录下创建 UserData.aidl:

// UserData.aidl
package com.example.service;

parcelable UserData;
  1. 创建 UserData 数据类
// UserData.kt
package com.example.service

import android.os.Parcel
import android.os.Parcelable

data class UserData(
    val userId: Int,
    val userName: String,
    val age: Int,
    val email: String
) : Parcelable {
    constructor(parcel: Parcel) : this(
        parcel.readInt(),
        parcel.readString() ?: "",
        parcel.readInt(),
        parcel.readString() ?: ""
    )

    override fun writeToParcel(parcel: Parcel, flags: Int) {
        parcel.writeInt(userId)
        parcel.writeString(userName)
        parcel.writeInt(age)
        parcel.writeString(email)
    }

    override fun describeContents(): Int = 0

    companion object CREATOR : Parcelable.Creator<UserData> {
        override fun createFromParcel(parcel: Parcel): UserData {
            return UserData(parcel)
        }

        override fun newArray(size: Int): Array<UserData?> {
            return arrayOfNulls(size)
        }
    }
}
  1. 服务端实现

服务端 Service 实现:

// UserManagerService.kt
package com.example.server

import android.app.Service
import android.content.Intent
import android.os.IBinder
import android.os.RemoteCallbackList
import android.os.RemoteException
import android.util.Log
import com.example.service.IUserManager
import com.example.service.IUserCallback
import com.example.service.UserData

class UserManagerService : Service() {
    
    companion object {
        private const val TAG = "UserManagerService"
    }
    
    // 用户数据存储
    private val userList = mutableListOf<UserData>()
    private var userIdCounter = 1
    
    // 回调监听器列表(使用 RemoteCallbackList 自动处理进程死亡)
    private val callbackList = RemoteCallbackList<IUserCallback>()
    
    // Binder 实现
    private val binder = object : IUserManager.Stub() {
        
        @Throws(RemoteException::class)
        override fun addUser(user: UserData): Int {
            synchronized(userList) {
                val newUser = user.copy(userId = userIdCounter++)
                userList.add(newUser)
                Log.d(TAG, "用户添加成功: ${newUser.userName}, ID: ${newUser.userId}")
                
                // 通知所有监听器
                notifyUserAdded(newUser)
                notifyUserCountChanged(userList.size)
                
                return newUser.userId
            }
        }
        
        @Throws(RemoteException::class)
        override fun deleteUser(userId: Int): Boolean {
            synchronized(userList) {
                val iterator = userList.iterator()
                while (iterator.hasNext()) {
                    val user = iterator.next()
                    if (user.userId == userId) {
                        iterator.remove()
                        Log.d(TAG, "用户删除成功: $userId")
                        
                        // 通知所有监听器
                        notifyUserDeleted(userId)
                        notifyUserCountChanged(userList.size)
                        
                        return true
                    }
                }
                return false
            }
        }
        
        @Throws(RemoteException::class)
        override fun getUserList(): MutableList<UserData> {
            synchronized(userList) {
                return ArrayList(userList)
            }
        }
        
        @Throws(RemoteException::class)
        override fun getUserCount(): Int {
            synchronized(userList) {
                return userList.size
            }
        }
        
        @Throws(RemoteException::class)
        override fun registerListener(callback: IUserCallback) {
            callbackList.register(callback)
            Log.d(TAG, "监听器注册成功, 当前监听器数量: ${callbackList.registeredCallbackCount}")
        }
        
        @Throws(RemoteException::class)
        override fun unregisterListener(callback: IUserCallback) {
            callbackList.unregister(callback)
            Log.d(TAG, "监听器注销成功, 当前监听器数量: ${callbackList.registeredCallbackCount}")
        }
    }
    
    override fun onBind(intent: Intent): IBinder {
        Log.d(TAG, "服务被绑定")
        return binder
    }
    
    override fun onCreate() {
        super.onCreate()
        Log.d(TAG, "用户管理服务创建")
        
        // 添加一些测试数据
        addTestData()
    }
    
    override fun onDestroy() {
        super.onDestroy()
        callbackList.kill()
        Log.d(TAG, "用户管理服务销毁")
    }
    
    private fun addTestData() {
        val testUsers = listOf(
            UserData(0, "张三", 25, "zhangsan@example.com"),
            UserData(0, "李四", 30, "lisi@example.com")
        )
        
        testUsers.forEach { user ->
            binder.addUser(user)
        }
    }
    
    // 通知用户添加
    private fun notifyUserAdded(user: UserData) {
        val count = callbackList.beginBroadcast()
        try {
            for (i in 0 until count) {
                try {
                    callbackList.getBroadcastItem(i).onUserAdded(user)
                } catch (e: RemoteException) {
                    Log.e(TAG, "通知用户添加失败", e)
                }
            }
        } finally {
            callbackList.finishBroadcast()
        }
    }
    
    // 通知用户删除
    private fun notifyUserDeleted(userId: Int) {
        val count = callbackList.beginBroadcast()
        try {
            for (i in 0 until count) {
                try {
                    callbackList.getBroadcastItem(i).onUserDeleted(userId)
                } catch (e: RemoteException) {
                    Log.e(TAG, "通知用户删除失败", e)
                }
            }
        } finally {
            callbackList.finishBroadcast()
        }
    }
    
    // 通知用户数量变化
    private fun notifyUserCountChanged(count: Int) {
        val callbackCount = callbackList.beginBroadcast()
        try {
            for (i in 0 until callbackCount) {
                try {
                    callbackList.getBroadcastItem(i).onUserCountChanged(count)
                } catch (e: RemoteException) {
                    Log.e(TAG, "通知用户数量变化失败", e)
                }
            }
        } finally {
            callbackList.finishBroadcast()
        }
    }
}

服务端 AndroidManifest.xml 配置:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.server">

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme">
        
        <service
            android:name=".UserManagerService"
            android:enabled="true"
            android:exported="true">
            <intent-filter>
                <action android:name="com.example.service.USER_MANAGER_SERVICE" />
            </intent-filter>
        </service>

        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>
  1. 客户端实现

客户端 ServiceConnection:

// UserManagerClient.kt
package com.example.client

import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.content.ServiceConnection
import android.os.IBinder
import android.os.RemoteException
import android.util.Log
import com.example.service.IUserManager
import com.example.service.IUserCallback
import com.example.service.UserData

class UserManagerClient(private val context: Context) {
    
    companion object {
        private const val TAG = "UserManagerClient"
        private const val SERVICE_ACTION = "com.example.service.USER_MANAGER_SERVICE"
        private const val SERVICE_PACKAGE = "com.example.server" // 服务端包名
    }
    
    private var userManager: IUserManager? = null
    private var isServiceBound = false
    
    // 回调监听器
    private val userCallback = object : IUserCallback.Stub() {
        @Throws(RemoteException::class)
        override fun onUserAdded(user: UserData) {
            Log.d(TAG, "回调: 用户添加 - ${user.userName} (ID: ${user.userId})")
            // 在主线程更新UI
            android.os.Handler(context.mainLooper).post {
                onUserAddedCallback?.invoke(user)
            }
        }
        
        @Throws(RemoteException::class)
        override fun onUserDeleted(userId: Int) {
            Log.d(TAG, "回调: 用户删除 - ID: $userId")
            android.os.Handler(context.mainLooper).post {
                onUserDeletedCallback?.invoke(userId)
            }
        }
        
        @Throws(RemoteException::class)
        override fun onUserCountChanged(count: Int) {
            Log.d(TAG, "回调: 用户数量变化 - $count")
            android.os.Handler(context.mainLooper).post {
                onUserCountChangedCallback?.invoke(count)
            }
        }
    }
    
    // 客户端回调接口
    var onUserAddedCallback: ((UserData) -> Unit)? = null
    var onUserDeletedCallback: ((Int) -> Unit)? = null
    var onUserCountChangedCallback: ((Int) -> Unit)? = null
    
    // Service 连接
    private val serviceConnection = object : ServiceConnection {
        override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
            Log.d(TAG, "服务连接成功")
            userManager = IUserManager.Stub.asInterface(service)
            isServiceBound = true
            
            // 注册回调监听器
            try {
                userManager?.registerListener(userCallback)
                Log.d(TAG, "回调监听器注册成功")
            } catch (e: RemoteException) {
                Log.e(TAG, "注册回调监听器失败", e)
            }
            
            onConnectedCallback?.invoke()
        }
        
        override fun onServiceDisconnected(name: ComponentName?) {
            Log.d(TAG, "服务连接断开")
            isServiceBound = false
            userManager = null
            onDisconnectedCallback?.invoke()
        }
    }
    
    var onConnectedCallback: (() -> Unit)? = null
    var onDisconnectedCallback: (() -> Unit)? = null
    
    // 绑定服务
    fun bindService() {
        Log.d(TAG, "开始绑定服务")
        val intent = Intent(SERVICE_ACTION)
        intent.`package` = SERVICE_PACKAGE // 设置包名确保找到正确服务
        
        try {
            val result = context.bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE)
            if (!result) {
                Log.e(TAG, "绑定服务失败")
            }
        } catch (e: Exception) {
            Log.e(TAG, "绑定服务异常", e)
        }
    }
    
    // 解绑服务
    fun unbindService() {
        if (isServiceBound) {
            try {
                userManager?.unregisterListener(userCallback)
            } catch (e: RemoteException) {
                Log.e(TAG, "注销回调监听器失败", e)
            }
            
            context.unbindService(serviceConnection)
            isServiceBound = false
            userManager = null
            Log.d(TAG, "服务解绑成功")
        }
    }
    
    // 添加用户
    fun addUser(userName: String, age: Int, email: String): Int? {
        if (!isServiceBound) {
            Log.w(TAG, "服务未绑定,无法添加用户")
            return null
        }
        
        return try {
            val user = UserData(0, userName, age, email)
            userManager?.addUser(user)
        } catch (e: RemoteException) {
            Log.e(TAG, "添加用户失败", e)
            null
        }
    }
    
    // 删除用户
    fun deleteUser(userId: Int): Boolean {
        if (!isServiceBound) {
            Log.w(TAG, "服务未绑定,无法删除用户")
            return false
        }
        
        return try {
            userManager?.deleteUser(userId) ?: false
        } catch (e: RemoteException) {
            Log.e(TAG, "删除用户失败", e)
            false
        }
    }
    
    // 获取用户列表
    fun getUserList(): List<UserData> {
        if (!isServiceBound) {
            Log.w(TAG, "服务未绑定,无法获取用户列表")
            return emptyList()
        }
        
        return try {
            userManager?.getUserList() ?: emptyList()
        } catch (e: RemoteException) {
            Log.e(TAG, "获取用户列表失败", e)
            emptyList()
        }
    }
    
    // 获取用户数量
    fun getUserCount(): Int {
        if (!isServiceBound) {
            Log.w(TAG, "服务未绑定,无法获取用户数量")
            return 0
        }
        
        return try {
            userManager?.getUserCount() ?: 0
        } catch (e: RemoteException) {
            Log.e(TAG, "获取用户数量失败", e)
            0
        }
    }
    
    // 检查服务是否绑定
    fun isBound(): Boolean = isServiceBound
}

客户端 Activity:

// MainActivity.kt
package com.example.client

import android.os.Bundle
import android.widget.Button
import android.widget.EditText
import android.widget.TextView
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import com.example.service.UserData

class MainActivity : AppCompatActivity() {
    
    private lateinit var userManagerClient: UserManagerClient
    private lateinit var logTextView: TextView
    private lateinit var userCountText: TextView
    private lateinit var nameEditText: EditText
    private lateinit var ageEditText: EditText
    private lateinit var emailEditText: EditText
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        
        initViews()
        initUserManagerClient()
    }
    
    private fun initViews() {
        logTextView = findViewById(R.id.log_text_view)
        userCountText = findViewById(R.id.user_count_text)
        nameEditText = findViewById(R.id.name_edit_text)
        ageEditText = findViewById(R.id.age_edit_text)
        emailEditText = findViewById(R.id.email_edit_text)
        
        findViewById<Button>(R.id.bind_button).setOnClickListener { bindService() }
        findViewById<Button>(R.id.unbind_button).setOnClickListener { unbindService() }
        findViewById<Button>(R.id.add_user_button).setOnClickListener { addUser() }
        findViewById<Button>(R.id.delete_last_button).setOnClickListener { deleteLastUser() }
        findViewById<Button>(R.id.get_list_button).setOnClickListener { getUserList() }
        findViewById<Button>(R.id.get_count_button).setOnClickListener { getUserCount() }
    }
    
    private fun initUserManagerClient() {
        userManagerClient = UserManagerClient(this)
        
        // 设置连接状态回调
        userManagerClient.onConnectedCallback = {
            runOnUiThread {
                addLog("服务连接成功")
                updateUserCount()
            }
        }
        
        userManagerClient.onDisconnectedCallback = {
            runOnUiThread {
                addLog("服务连接断开")
                userCountText.text = "服务未连接"
            }
        }
        
        // 设置用户事件回调
        userManagerClient.onUserAddedCallback = { user ->
            addLog("回调: 用户添加 - ${user.userName} (ID: ${user.userId})")
            updateUserCount()
        }
        
        userManagerClient.onUserDeletedCallback = { userId ->
            addLog("回调: 用户删除 - ID: $userId")
            updateUserCount()
        }
        
        userManagerClient.onUserCountChangedCallback = { count ->
            addLog("回调: 用户数量变化 - $count")
            updateUserCount()
        }
    }
    
    private fun bindService() {
        userManagerClient.bindService()
        addLog("正在绑定服务...")
    }
    
    private fun unbindService() {
        userManagerClient.unbindService()
        addLog("服务已解绑")
    }
    
    private fun addUser() {
        val name = nameEditText.text.toString().trim()
        val ageText = ageEditText.text.toString().trim()
        val email = emailEditText.text.toString().trim()
        
        if (name.isEmpty() || ageText.isEmpty() || email.isEmpty()) {
            Toast.makeText(this, "请填写完整用户信息", Toast.LENGTH_SHORT).show()
            return
        }
        
        val age = ageText.toIntOrNull() ?: 0
        if (age <= 0) {
            Toast.makeText(this, "请输入有效的年龄", Toast.LENGTH_SHORT).show()
            return
        }
        
        val userId = userManagerClient.addUser(name, age, email)
        if (userId != null) {
            addLog("添加用户成功: $name (ID: $userId)")
            // 清空输入框
            nameEditText.text.clear()
            ageEditText.text.clear()
            emailEditText.text.clear()
        } else {
            addLog("添加用户失败: 服务未连接")
        }
    }
    
    private fun deleteLastUser() {
        val userList = userManagerClient.getUserList()
        if (userList.isNotEmpty()) {
            val lastUser = userList.last()
            val success = userManagerClient.deleteUser(lastUser.userId)
            if (success) {
                addLog("删除用户成功: ${lastUser.userName} (ID: ${lastUser.userId})")
            } else {
                addLog("删除用户失败")
            }
        } else {
            addLog("没有用户可删除")
        }
    }
    
    private fun getUserList() {
        val userList = userManagerClient.getUserList()
        addLog("当前用户列表:")
        if (userList.isEmpty()) {
            addLog("  暂无用户")
        } else {
            userList.forEach { user ->
                addLog("  ${user.userName} (ID: ${user.userId}, 年龄: ${user.age})")
            }
        }
    }
    
    private fun getUserCount() {
        val count = userManagerClient.getUserCount()
        addLog("当前用户数量: $count")
        updateUserCount()
    }
    
    private fun updateUserCount() {
        if (userManagerClient.isBound()) {
            val count = userManagerClient.getUserCount()
            userCountText.text = "用户数量: $count"
        } else {
            userCountText.text = "服务未连接"
        }
    }
    
    private fun addLog(message: String) {
        runOnUiThread {
            val currentText = logTextView.text.toString()
            val newText = if (currentText.isEmpty()) {
                message
            } else {
                "$currentText\n$message"
            }
            logTextView.text = newText
        }
    }
    
    override fun onDestroy() {
        super.onDestroy()
        userManagerClient.unbindService()
    }
}

关键注意事项

  1. 跨进程数据传递
  • 所有通过 AIDL 传递的数据必须实现 Parcelable 接口
  • 基本数据类型、String、List、Map 等可以直接传递
  1. 回调监听器管理
  • 使用 RemoteCallbackList 管理回调,自动处理进程死亡
  • 回调方法会在 Binder 线程池中执行,需要切换到主线程更新 UI
  1. 异常处理
  • 所有 AIDL 方法调用都要捕获 RemoteException
  • 服务断开时要清理资源
  1. 服务绑定
  • 使用明确的 Intent Action 和 Package 名称
  • 及时在 onDestroy 中解绑服务

这个完整实例演示了 AIDL 通信的核心功能,包括:

· 基本数据操作(增删改查) · 回调监听机制 · 服务生命周期管理 · 异常处理 · 跨进程数据传递

可以根据需要扩展这个基础框架。


Android的AIDL(Android Interface Definition Language,安卓接口定义语言)是面试中跨进程通信部分的必考核心。下面我将从基础概念、工作原理、使用步骤、高级特性到面试题集,为你进行全面总结。

一、核心概念与要解决的问题

首先,理解AIDL的存在意义是关键,面试官常以此开场。

  • 是什么:AIDL是一种IDL语言,用于定义跨进程通信的接口。它生成了一个Binder代理类的Java代码框架,开发者只需填充具体实现。
  • 为什么需要:Android为每个应用分配独立的沙盒进程,内存不共享。当需要数据交互或能力调用时(如音乐App向系统服务请求音频焦点),就必须进行IPC。
  • 与直接使用Binder的关系:AIDL是Binder的高级封装。手动实现Binder需要重写 onTransact 和 transact 方法,处理序列化等复杂细节;而AIDL自动生成了这些样板代码,让开发者聚焦业务逻辑。

二、AIDL的工作原理与通信流程

这是理解AIDL的基石。其核心是基于 Binder驱动 的 C/S 架构。

sequenceDiagram
    participant Client
    participant Stub_Proxy (AIDL生成)
    participant Binder Driver
    participant Stub (AIDL生成)
    participant ServerImpl (开发者实现)

    Note over Client, ServerImpl: 1. 建立连接
    Client->>Stub_Proxy (AIDL生成): 绑定服务,获取Binder代理对象
    Stub_Proxy (AIDL生成)-->>Client: 返回Proxy

    Note over Client, ServerImpl: 2. 发起远程调用(以addBook为例)
    Client->>Stub_Proxy (AIDL生成): 调用 addBook(book)
    Stub_Proxy (AIDL生成)->>Stub_Proxy (AIDL生成): 1. 序列化参数(Parcel)
    Stub_Proxy (AIDL生成)->>Binder Driver: 2. 调用 transact()
    Binder Driver->>Stub (AIDL生成): 3. 路由到服务端 onTransact()
    Stub (AIDL生成)->>Stub (AIDL生成): 4. 反序列化参数
    Stub (AIDL生成)->>ServerImpl (开发者实现): 5. 调用实际 addBook() 方法
    ServerImpl (开发者实现)->>ServerImpl (开发者实现): 6. 执行逻辑
    ServerImpl (开发者实现)-->>Stub (AIDL生成): 7. 返回结果
    Stub (AIDL生成)->>Stub (AIDL生成): 8. 序列化返回值(Parcel)
    Stub (AIDL生成)-->>Binder Driver: 9. 返回结果
    Binder Driver-->>Stub_Proxy (AIDL生成): 10. 返回结果
    Stub_Proxy (AIDL生成)->>Stub_Proxy (AIDL生成): 11. 反序列化返回值
    Stub_Proxy (AIDL生成)-->>Client: 12. 返回最终结果给调用者

理解上图中的两个核心角色:

  • Proxy(代理):在客户端,由AIDL生成。它负责将调用打包(序列化)并通过Binder驱动发送出去。
  • Stub(桩):在服务端,由AIDL生成并作为基类。它负责解包(反序列化)请求,并调用开发者编写的实际方法。

三、高级特性与核心机制(面试深入考察点)

这是区分你是否真正精通的关键。

定向Tag:in, out, inout

  • in(默认):数据仅从客户端流向服务端。服务端修改参数,客户端对象不受影响。
  • out:数据仅从服务端流回客户端。客户端传入的对象(字段初始值不重要),服务端可填充数据并传回。
  • inout:双向流通。
  • 原理:影响 Parcel 的序列化/反序列化流程。out 和 inout 会重新从Parcel中反序列化生成新对象并赋值回客户端参数。
  • 性能建议:若无必要,优先使用 in,因为 out/inout 会触发额外的序列化开销。

oneway 关键字

  • 用于修饰AIDL方法,如 oneway void doSomething();。
  • 作用:使方法调用变为异步非阻塞。客户端调用后立即返回,无需等待服务端处理。
  • 限制:不能有返回值,也不能声明 throws 异常。

线程模型与安全性

  • 服务端方法执行线程:Binder线程池。默认情况下,你的服务端实现必须处理并发调用,确保线程安全。
  • 客户端调用线程:如果从UI线程发起调用,会阻塞UI线程(同步调用)。因此,强烈建议在客户端将AIDL调用置于子线程。

异常处理

  • 服务端抛出的 RemoteException 表示通信过程失败(如连接断开)。
  • 服务端抛出的其他异常(如 SecurityException)会传递到客户端,但会重新包装。需要在AIDL接口方法上显式声明 throws。

死亡代理 (linkToDeath & unlinkToDeath)

  • 客户端可以给Binder对象注册一个死亡代理,当服务端进程意外终止时,客户端能收到回调并进行重连等恢复操作。

四、典型面试问题与回答思路

  1. AIDL是什么?解决了什么问题?
  • 思路:从Android进程沙盒机制引出IPC需求,说明AIDL是用于定义IPC接口的IDL,它能自动生成Binder通信的复杂模板代码。
  1. 简述一次AIDL调用的完整流程。
  • 思路:按照【工作原理】部分的流程图,清晰描述从客户端Proxy序列化,经Binder驱动,到服务端Stub反序列化并执行,再原路返回的过程。
  1. AIDL支持哪些数据类型?
  • 思路:分两类回答。基本类型:Java所有基本类型(如int、long)、String、CharSequence、List/Map(其内元素也须支持)。特殊类型:实现 Parcelable 的对象、其他AIDL接口、IBinder。
  1. 定向Tag in, out, inout 有什么区别?
  • 思路:从数据流向和性能开销两方面对比。强调默认是 in,以及 out/inout 会引发额外的反序列化操作。
  1. oneway 关键字有什么用?
  • 思路:声明它为异步非阻塞调用。立刻回答其限制:不能有返回值,不能抛出异常。
  1. AIDL调用是同步还是异步?会阻塞UI线程吗?
  • 思路:明确指出默认是同步的。如果客户端在UI线程调用,就会阻塞UI线程。因此最佳实践是在后台线程进行AIDL调用。
  1. 服务端执行AIDL方法在什么线程?需要注意什么?
  • 思路:在Binder线程池中执行。必须注意多线程并发安全问题,对共享数据的访问要加锁或使用并发容器。
  1. 如何传递一个自定义类型(如Book)?
  • 思路:必须让该类实现 Parcelable 接口,并详细说明步骤:
    1. 实现接口;
    2. 编写 writeToParcel 和 describeContents;
    3. 添加静态 CREATOR 字段;
    4. 在AIDL文件中声明。
  1. 客户端如何感知服务端进程死亡?
  • 思路:通过 linkToDeath 注册死亡代理。当服务端进程终止,客户端的 DeathRecipient 回调会被触发,可在其中进行重连或清理。
  1. AIDL和Messenger、ContentProvider在IPC场景下如何选择?
  • 思路:这是架构题。AIDL:适用于方法调用复杂、需要高并发、有同步返回的场景。Messenger:基于AIDL封装,适用于简单的消息队列式通信,底层串行处理。ContentProvider:主要用于数据共享,提供CRUD接口。