4.4 使用AIDL实现进程间通信
1, Messenger分析
Messenger是以串行的方式来处理客户端的请求的.如果大量消息同时发送到服务端,
服务端仍然只能一个一个的处理.如果有大量的并发请求那么Messenger就不太合适了
同时,Messenger的主要是为了传递消息.很多时候我们需要跨进程调用服务端的方法,
这种情况下Messenger就无法做到了.---此时就可以使用AIDL.Messenger的底层也是
通过AIDL实现的.
2, 实现步骤 :
服务端
- 创建一个Service用来监听客户端的连接请求.
- 创建一个AIDL文件,将要暴露给客户端的接口在这个AIDL文件中声明.
- 在这个Service中实现接口中的方法.
客户端
- 拷贝服务端的AIDL文件(最好是整个包,客户端和服务端的AIDL包名一定要保持一致).
- 绑定服务端的Service.
- 绑定成功后,将服务端返回的Binder对象转换成AIDL所属的的类型.
- 调用AIDL中的方法.
AIDL的声明.
// IBookManager.aidl
package com.blx.smokepay.myapplication;
// Declare any non-default types here with import statements
interface IBookManager {
void addBook(in String name);
}
AIDL中支持的数据类型 :
1, 基本数据类型 : int long char boolean double 等.
2, String 和 CharSequence.
3, List 只支持 ArrayList 里面的每一个元素都必须可以被AIDL支持.
4, Map 只支持HashMap.
5, Parcelable : 所有实现了Parcelable接口的对象.
6, AIDL: 所有的AIDL接口本身也可以在AIDL文件中使用.
1, 其中自定义的Parcelable对象和AIDL支持的对象都必须显式 import 进来.
2, 如果AIDL用到Parcelable对象那么必须新建一个和他同名的AIDL文件并在其中声明他为Parcelable类型.
3, 除了基本类型以外的其他类型的数据都必须表明 : in out inout
RemoteCallbackList 接口
1, RemoteCallbackList : 是系统专门提供用于删除跨程序listener的接口.
RemoteCallbackList是一个接口 ,
2, 支持管理任意的AIDL接口.
3, RemoteCallbackList 内部自动实现了线程同步功能.
注意点
1, 客户端调用远程服务里的方法.被调用的方法运行在服务端的 Binder 线程池中,同时客户端
线程会被挂起,这个时候如果服务端方法比较耗时,就会造成客户端线程长时间被阻塞在这里
如果客户端的线程是UI线程,就会导致ANR.因此,当知道远程服务里的某个方法比较耗时,那就
避免在客户端UI线程中访问该方法.
2, 客户端的onServiceConnected() 和 onServiceDisconnected() 方法都是运行在客户端UI线程中
因此,避免在这些方法中调用服务端耗时方法.
3, 服务端方法本身就是运行在服务端的Binder线程池中 , 所以服务器端方法本身就可以进行耗时操作,
这个时候切记不要在服务端方法中开启线程执行异步任务.
4, 同时远程服务端需要调用客户端的listener的时候,被调用的方法运行在客户端的Binder线程池中
因此需要注意服务端也不要调用耗时的客户端方法.
Binder意外死亡
由于服务端进程意外死亡,这时我们需要重新连接服务.有两种方法:
1, 为 Binder 设置 DeathRecipient 监听.当 Binder 死亡时我们会收到 binderDied 方法回调.在
binderDied 方法中设置重新连接服务.
2, 在 onServiceDisconnected() 方法中重新连接服务.
权限验证
1, 在onBinder中进行验证,验证不通过直接返回null.
2, 在onTransact 方法中进行验证,验证不通过返回false.
验证方法:
1, permission
2, Uid
示例代码
服务端
public class BookManagerService extends Service {
private static final String TAG = "BookManagerService";
/**
* CopyOnWriteArrayList 支持并发读/写 , AIDL 方法是在服务端的Binder线程池中执行的.
* 因此,当多个客户端同时连接的时候回出现多个线程同时访问的情况,因此使用CopyOnWriteArrayList
* 来进行自动线程同步处理.
*/
private CopyOnWriteArrayList<String> mBookList = new CopyOnWriteArrayList<>();
/**
* 观察者对象数组.
* RemoteCallbackList : 是系统专门提供用于删除跨程序listener的接口.RemoteCallbackList是一个接口
* 支持管理任意的AIDL接口.
* RemoteCallbackList 内部自动实现了线程同步功能.
*/
private RemoteCallbackList<IOnNewBookListener> mIOnNewBookListeners = new RemoteCallbackList<>();
private Binder mBinder = new IBookManager.Stub(){
@Override
public void addBook(String name) throws RemoteException {
Log.i(TAG, "addBook: 添加新书 : " + name);
mBookList.add(name);
// 通知观察者. begin finish 必须配合使用.
final int N = mIOnNewBookListeners.beginBroadcast();
for (int i = 0; i < N; i++) {
IOnNewBookListener listener = mIOnNewBookListeners.getBroadcastItem(i);
// 注意 : onNewBookArrived()方法会在服务端的Binder线程池中执行.不能进行UI操作.
if (listener != null)
listener.onNewBookArrived(name);
}
mIOnNewBookListeners.finishBroadcast();
}
/**
* 添加观察者.
* @param listener
* @throws RemoteException
*/
@Override
public void addListener(IOnNewBookListener listener) throws RemoteException {
mIOnNewBookListeners.register(listener);
Log.i(TAG, "addListener: 添加新的观察者");
}
/**
* 删除观察者.
* @param listener
* @throws RemoteException
*/
@Override
public void removeListener(IOnNewBookListener listener) throws RemoteException {
mIOnNewBookListeners.unregister(listener);
Log.i(TAG, "removeListener: 删除一个观察者");
}
};
@Override
public void onCreate() {
super.onCreate();
mBookList.add("账单");
mBookList.add("菜单");
}
public BookManagerService() {
}
/**
* 返回服务端的Binder对象.
* @param intent intent
* @return
* 服务端的Binder对象.
*/
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
}
客户端
/**
* 客户端进程.
* Created by WSJ on 2016/9/29.
*/
public class BookManagerActivity extends Activity {
private static final String TAG = "BookManagerActivity";
private IBookManager mIBookManager ;
/**
* 监听者对象.
*/
private IOnNewBookListener mIOnNewBookListener = new IOnNewBookListener.Stub() {
/**
* 新书监听
* 注意 : 这个方法在服务端的Binder线程池中进行,因此不能进行UI操作.
* @param book 书名.
* @throws RemoteException
*/
@Override
public void onNewBookArrived(String book) throws RemoteException {
Message msg = Message.obtain();
msg.obj = book;
msg.what = 1;
mHandler.sendMessage(msg);
}
};
private Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
switch (msg.what){
case 1:
Log.i(TAG, "handleMessage: 增加新书 : " + msg.obj);
break;
}
}
};
/**
* 用于连接服务端的Connection对象.
*/
private ServiceConnection mConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
// 将服务端的Binder对象转换成,AIDL接口类对象.
mIBookManager = IBookManager.Stub.asInterface(service);
// 注册监听者.
try {
mIBookManager.addListener(mIOnNewBookListener);
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
mIBookManager = null;
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 绑定远程服务.
Intent intent = new Intent(this, BookManagerService.class);
bindService(intent,mConnection,BIND_AUTO_CREATE);
}
/**
* 解除服务绑定.
* 注销监听.
*/
@Override
protected void onDestroy() {
if (mIBookManager != null && mIBookManager.asBinder().isBinderAlive()){
Log.i(TAG, "onDestroy: 注销监听");
try {
mIBookManager.removeListener(mIOnNewBookListener);
} catch (RemoteException e) {
e.printStackTrace();
}
}
if (mConnection != null)
unbindService(mConnection);
super.onDestroy();
}
public void clicked(View view) throws RemoteException {
mIBookManager.addBook("忘了我");
}
}
备注 : Android开发艺术探索