Android AIDL 详解

116 阅读5分钟

developer.android.google.cn/guide/compo…

一、AIDL 核心知识点

1. 基础类型支持

类型说明注意事项
所有基本类型int, long, char, boolean, float, double, byte不支持 short(可用int替代)
String & CharSequenceUTF-8 字符串跨进程传递自动转换
ArrayList动态数组实际接收类型固定为 ArrayList,元素必须是 AIDL 支持类型
HashMap键值对集合实际接收类型固定为 HashMap,Key/Value 都需 AIDL 支持
Parcelable 对象实现 Parcelable 接口的对象包括 Android 的 Bundle
AIDL 接口其他 AIDL 定义的接口不支持普通 Java 接口

重要限制

  • 不支持泛型声明(如 Map<String,Integer>
  • 集合嵌套时,所有层级元素都需符合 AIDL 类型要求
  • 文件描述符(FileDescriptor) 需使用 @fd 注解

2. Parcelable 对象实现

// Book.java
public class Book implements Parcelable {
    private String title;
    private double price;

    protected Book(Parcel in) {
        title = in.readString();
        price = in.readDouble();
    }

    public static final Creator<Book> CREATOR = new Creator<Book>() {
        @Override
        public Book createFromParcel(Parcel in) {
            return new Book(in);
        }

        @Override
        public Book[] newArray(int size) {
            return new Book[size];
        }
    };

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeString(title);
        dest.writeDouble(price);
    }

    @Override
    public int describeContents() {
        return 0;
    }
    
    //省略get/set方法
}
// Book.aidl
parcelable Book;

二、参数修饰符详解

修饰符数据流向服务端获取对象数据修改同步到客户端适用场景
inClient → Server✔️只读输入参数
outClient ← Server✔️输出型参数
inoutClient ↔ Server✔️✔️双向参数

规则

  1. 基本类型和String/CharSequence默认 in,可不显式声明```
  2. 所有非基本类型参数 必须 明确指定 in/out/inout

示例代码

// 定义 Parcelable 对象
parcelable UserData;

interface IUserService {
    // in 示例:传递用户ID(基本类型)
    UserData getUser(in long userId);
    
    // out 示例:获取服务状态(对象)
    void getServiceStatus(out Bundle status);
    
    // inout 示例:更新用户信息(双向)
    void updateUser(inout UserData user);
    
    // String 默认 in(可不声明)
    void logEvent(String eventName);
}

oneway 方法修饰符

核心特性

oneway void asyncTask(in int param);
特性说明
异步调用客户端立即返回,不阻塞
无返回值必须声明为 void
参数限制所有参数需为基本类型或 in 修饰
执行顺序不保证调用顺序
执行线程服务端在 独立Binder线程 执行

适用场景

  1. 不需要返回结果的操作(如日志记录、通知)
  2. 耗时操作但不需要客户端等待(如数据备份)
  3. 高频率调用的非关键操作

禁止场景

// 错误示例1:有返回值
oneway int getStatus(); // 编译错误!

// 错误示例2:使用 out 参数
oneway void processData(out Result result); // 编译错误!

三、AIDL 接口使用

1. AIDL 接口作为参数

// IOperationCallback.aidl
interface IOperationCallback {
    oneway void onSuccess(in String result);
    oneway void onFailure(in String error);
}

// IDataService.aidl
import com.example.IOperationCallback;

interface IDataService {
    void fetchData(in String query, in IOperationCallback callback);
}

2. 服务端实现

public class DataServiceImpl extends IDataService.Stub {
    @Override
    public void fetchData(String query, IOperationCallback callback) {
        try {
            String result = processQuery(query); // 耗时操作
            callback.onSuccess(result);
        } catch (Exception e) {
            callback.onFailure(e.getMessage());
        }
    }
}

3. 客户端使用

// 创建回调实现
private IOperationCallback callback = new IOperationCallback.Stub() {
    @Override
    public void onSuccess(String result) {
        runOnUiThread(() -> updateUI(result));
    }

    @Override
    public void onFailure(String error) {
        runOnUiThread(() -> showError(error));
    }
};

// 调用远程服务
dataService.fetchData("search_term", callback);

四、死亡通知机制(服务异常处理)

1. 注册死亡通知

private IBinder.DeathRecipient deathRecipient = new IBinder.DeathRecipient() {
    @Override
    public void binderDied() {
        Log.w(TAG, "远程服务已终止");
        // 1. 清理资源
        mService = null;
        // 2. 尝试重新连接
        reconnectToService();
    }
};

private void bindService() {
    bindService(intent, connection, Context.BIND_AUTO_CREATE);
}

private ServiceConnection connection = new ServiceConnection() {
    @Override
    public void onServiceConnected(ComponentName name, IBinder service) {
        mService = IDataService.Stub.asInterface(service);
        try {
            // 注册死亡通知
            service.linkToDeath(deathRecipient, 0);
        } catch (RemoteException e) {
            e.printStackTrace();
        }
    }
};

2. 处理服务崩溃

@Override
protected void onDestroy() {
    super.onDestroy();
    if (mService != null) {
        mService.asBinder().unlinkToDeath(deathRecipient, 0);
        unbindService(connection);
    }
}

private void reconnectToService() {
    unbindService(connection); // 先解绑旧连接
    new Handler(Looper.getMainLooper()).postDelayed(() -> {
        bindService(intent, connection, Context.BIND_AUTO_CREATE);
    }, 3000);
}

四、综合示例:图书管理系统

1. AIDL 文件定义

// IBookManager.aidl
import com.example.Book;
import com.example.IBookEventListener;

interface IBookManager {
    // 添加图书(inout 双向修改)
    void addBook(inout Book book);
    
    // 获取图书列表
    List<Book> getBooks();
    
    // 注册事件监听器
    void registerListener(in IBookEventListener listener);
    
    // 注销事件监听器
    void unregisterListener(in IBookEventListener listener);
    
    // 异步添加图书(oneway)
    oneway void addBookAsync(in Book book);
}

// IBookEventListener.aidl
oneway interface IBookEventListener {
    void onBookAdded(in Book newBook);
    void onBookRemoved(in String bookTitle);
}

2. 服务端关键实现

public class BookManagerService extends Service {
    private final CopyOnWriteArrayList<Book> mBooks = new CopyOnWriteArrayList<>();
    private final RemoteCallbackList<IBookEventListener> mListeners = new RemoteCallbackList<>();
    
    private final IBinder mBinder = new IBookManager.Stub() {
        @Override
        public void addBook(inout Book book) {
            book.setPrice(book.getPrice() * 0.9); // 打9折
            mBooks.add(book);
            notifyBookAdded(book);
        }
        
        @Override
        public List<Book> getBooks() {
            return new ArrayList<>(mBooks);
        }
        
        @Override
        public void registerListener(IBookEventListener listener) {
            if (listener != null) {
                mListeners.add(listener);
            }
        }
        
        @Override
        public void unregisterListener(IBookEventListener listener) {
            mListeners.remove(listener);
        }
        
        @Override
        public void addBookAsync(Book book) {
            // 后台处理
            new Thread(() -> {
                processBookInBackground(book);
                mBooks.add(book);
                notifyBookAdded(book);
            }).start();
        }
    };
    
    private void notifyBookAdded(Book book) {
        int count = mListeners.beginBroadcast();
        for (int i = 0; i < count; i++) {
            try {
                mListeners.getBroadcastItem(i).onBookAdded(book);
            } catch (RemoteException e) { /* 忽略断开连接 */ }
        }
        mListeners.finishBroadcast();
    }
}

3. 客户端完整实现

public class MainActivity extends AppCompatActivity {
    private IBookManager mBookManager;
    private final IBookEventListener mEventListener = new IBookEventListener.Stub() {
        @Override
        public void onBookAdded(Book newBook) {
            runOnUiThread(() -> showToast("新书添加: " + newBook.getTitle()));
        }
        
        @Override
        public void onBookRemoved(String bookTitle) {
            runOnUiThread(() -> showToast("书籍移除: " + bookTitle));
        }
    };
    
    private final ServiceConnection mConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            mBookManager = IBookManager.Stub.asInterface(service);
            try {
                // 注册死亡通知
                service.linkToDeath(() -> reconnectService(), 0);
                
                // 注册事件监听器
                mBookManager.registerListener(mEventListener);
                
                // 获取初始数据
                loadInitialBooks();
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }
        
        @Override
        public void onServiceDisconnected(ComponentName name) {
            mBookManager = null;
        }
    };
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        bindBookManagerService();
    }
    
    private void bindBookManagerService() {
        Intent intent = new Intent(this, BookManagerService.class);
        bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
    }
    
    private void addNewBook() {
        Book newBook = new Book("Android进阶指南", 99.9);
        if (mBookManager != null) {
            try {
                // 使用inout参数获取修改后的对象
                mBookManager.addBook(newBook);
                Log.d("BookInfo", "最终价格: " + newBook.getPrice()); // 显示折扣价
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }
    }
    
    @Override
    protected void onDestroy() {
        super.onDestroy();
        try {
            if (mBookManager != null) {
                mBookManager.unregisterListener(mEventListener);
                mBookManager.asBinder().unlinkToDeath(null, 0);
            }
        } catch (RemoteException e) {
            e.printStackTrace();
        }
        unbindService(mConnection);
    }
}

五、AIDL 最佳实践

  1. 线程管理

    • 服务端方法运行在 Binder 线程池(非 UI 线程)
    • 客户端回调运行在 Binder 线程(需切回 UI 线程更新界面)
  2. 异常处理

    try {
        mRemoteService.sensitiveOperation();
    } catch (RemoteException e) {
        // 处理进程间通信错误
    } catch (SecurityException e) {
        // 处理权限问题
    }
    
  3. 性能优化

    • 使用 oneway 修饰非关键异步操作
    • 避免在 AIDL 方法中进行同步阻塞操作
    • 避免在单个调用中传递超过 1MB 数据,大数据传输考虑使用 ContentProvider
  4. 安全机制

    <service
        android:name=".DataService"
        android:permission="com.example.PERMISSION_ACCESS_DATA">
        <intent-filter>
            <action android:name="com.example.DATA_SERVICE"/>
        </intent-filter>
    </service>
    
     // 服务端添加权限验证
     public boolean onTransact(int code, Parcel data, Parcel reply, int flags) {
         if (!checkCallingPermission("com.example.PERMISSION_ACCESS_DATA")) {
             throw new SecurityException("Permission denied");
         }
         return super.onTransact(code, data, reply, flags);
     }
    
  5. 版本兼容

    • 使用 @Nullable@NonNull 注解
    • 新增方法时考虑向后兼容
    • 使用版本号管理接口变更
     // 接口版本管理
     interface IBookManager {
         @VERSION(version = 2) // 标注接口版本
         List<Book> getBooks();
     }