- android进程间通讯开发了一套Binder机制,用来进行进程间通讯;
- 进程间传输涉及序列化,需要区分java的Serializable接口和Android的Parcelable接口;主要区别就是如果序列化后存储在设备中或者序列化后通过网络传输是用Serializable,内存序列化上使用Parcelabele
- 网上普遍说Parcelabele实现麻烦,使用【Android Parcelable code generator】插件就可以直接生成Parcelable相关代码
- 开启多进程模式是通过在清单文件内增加process属性,例如:
<service
android:name=".bind.BookManagerService"
android:process=":remote"/>
- 同一个应用内开启多进程模式后存在的问题如下:
1. Application会多次创建
2. 静态成员和单例模式失效
3. 线程同步失效
4.SharePreferce的可靠性降低
使用Binder是需要注意的事项有
服务端Binder意外死亡,客户端需要重启操作;
private IBinder.DeathRecipient mDeathRecipient = new IBinder.DeathRecipient() {
@Override
public void binderDied() {
restartServer(); //服务端意外死亡后重新连接的方式在客户端的Binder线程中
}
};
private void restartServer() {
Log.e(TAG, "mDeathRecipient-->binderDied-->");
if (mBookBinder == null) {
return;
}
mBookBinder.asBinder().unlinkToDeath(mDeathRecipient, 0);
mBookBinder = null;
Log.e(TAG, "mDeathRecipient-->bindService");
startBookService();
}
private void startBookService() {
Intent intent = new Intent(this, BookManagerService.class);
bindService(intent, connection, BIND_AUTO_CREATE);
}
private ServiceConnection connection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
// mBankBinder= IBankAIDL.Stub.asInterface(service);
mBookBinder = IBookManager.Stub.asInterface(service);
try {
service.linkToDeath(mDeathRecipient, 0);
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
Log.e(TAG, "onServiceDisconnected-->binder died");
// restartServer(); //服务端意外死亡后重新连接的方式在UI线程
}
};
权限校验,用来校验客户端的Binder
- 首先在服务端定义权限并且检查权限
在服务端清单中定义
<permission
android:name="com.xiaoma.brick.permission.ACCESS_BOOK_SERVICE"
android:protectionLevel="normal" />
在服务端的service中检查
@Override
public IBinder onBind(Intent intent) {
int check = checkCallingOrSelfPermission("com.xiaoma.brick.permission.ACCESS_BOOK_SERVICE");
Log.e(TAG, "onBind: "+check);
if(check==PackageManager.PERMISSION_DENIED){
Log.e(TAG, "onBind: 权限校验呢");
return null;
}
return mBinder;
}
- 在客户端增加权限
在客户端清单文件增加权限,通服务端保持一致
<uses-permission android:name="com.xiaoma.brick.permission.ACCESS_BOOK_SERVICE" />
- 如果应用内存在多个跨进程通过,存在多个服务的情况下,使用进程池服务统一处理;防止过多的跨进程服务
package com.xiaoma.brick.aidl;
// Declare any non-default types here with import statements
interface IBinderPool {
/**
* Demonstrates some basic types that you can use as parameters
* and return values in AIDL.
*/
IBinder queryBinder(int binderCode);
}
//跨进程服务使用线程池的话,就可以通过单例处理,保证唯一的
package com.xiaoma.brick.bind.impl;
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 com.xiaoma.brick.aidl.IBinderPool;
import java.util.concurrent.CountDownLatch;
public class BinderPool {
private final Context mContext;
private IBinderPool mBinderPool;
private static volatile BinderPool mInstance;
private CountDownLatch mCountDownLatch;
public static final int BINDER_BANK = 100;
public static final int BINDER_BOOK = 101;
private BinderPool(Context context) {
mContext = context.getApplicationContext();
connectBinderPoolService();
}
public static BinderPool getInstance(Context context) {
if (mInstance == null) {
synchronized (BinderPool.class) {
if (mInstance == null) {
mInstance = new BinderPool(context);
}
}
}
return mInstance;
}
private synchronized void connectBinderPoolService() {
mCountDownLatch = new CountDownLatch(1);
Intent service = new Intent(mContext, BinderPoolService.class);
mContext.bindService(service, mBinderPoolConnection, mContext.BIND_AUTO_CREATE);
try {
mCountDownLatch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
private ServiceConnection mBinderPoolConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
mBinderPool = IBinderPool.Stub.asInterface(service);
try {
mBinderPool.asBinder().linkToDeath(mBinderPoolDeathRecipient, 0);
} catch (RemoteException e) {
e.printStackTrace();
}
try {
mCountDownLatch.countDown();
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
private IBinder.DeathRecipient mBinderPoolDeathRecipient = new IBinder.DeathRecipient() {
@Override
public void binderDied() {
mBinderPool.asBinder().unlinkToDeath(mBinderPoolDeathRecipient, 0);
mBinderPool = null;
connectBinderPoolService();
}
};
public IBinder queryBinder(int binderCoder) {
IBinder binder = null;
try {
if (mBinderPool != null) {
binder = mBinderPool.queryBinder(binderCoder);
}
} catch (RemoteException e) {
e.printStackTrace();
}
return binder;
}
public static class BinderPollImpl extends IBinderPool.Stub {
public BinderPollImpl() {
super();
}
@Override
public IBinder queryBinder(int binderCode) throws RemoteException {
IBinder binder = null;
switch (binderCode) {
case BINDER_BANK:
binder = new BankBinderImpl();
break;
case BINDER_BOOK:
binder = new BookBinderImpl();
break;
default:
break;
}
return binder;
}
}
}
- RemoteCallbackList是系统专门提供的用于处理跨进程listener的接口
private RemoteCallbackList<IOnNewBookArrivedListener> mListenerList = new RemoteCallbackList<>();
//遍历listener集合
int N = mListenerList.beginBroadcast();
Log.e("xiaoma", "onNewBookedArrived ,notify listeners" +N);
for (int i = 0; i <N; i++) {
IOnNewBookArrivedListener iOnNewBookArrivedListener = mListenerList.getBroadcastItem(i);
Log.e("xiaoma", "onNewBookedArrived ,notify listeners" + iOnNewBookArrivedListener);
iOnNewBookArrivedListener.onNewBookArrived(book);
}
mListenerList.finishBroadcast();
- 多个客户端同事连接服务器的时候需要处理并发的情况,所以在AIDL方法中处理同步,直接使用CopyOnWriteArrayList来进行自动的线程同步
网友评论