本文基于《Android藝術(shù)探索》中知識的總結(jié)而創(chuàng)
1 簡介
1.1 簡述
IPC 進程間通訊或跨進程通訊
- android中IPC方式 Binder(AIDL)、Socket孔飒、Bundle鸦概、文件共享蒙挑、Messenger俯抖、ContentProvider
- IPC的基礎場景是多進程:一般由兩種颊糜,應用內(nèi)多進程模式拨与,應用間數(shù)據(jù)共享
1.2 進程與線程
- 線程是cpu調(diào)度的最小單位稻据,是一種有限的系統(tǒng)資源
- 進程指一個執(zhí)行單元,是一個獨立的應用或者程序
- 一個進程可包含多個線程
- ANR 主線程無響應买喧,以多線程解決
2 多進程模式
2.1 開啟
- 一般只有一種方法 就是在AndroidMenifest文件中給四大組件指定android:process屬性捻悯。
當然也可以通過JNI的natice層去fork匆赃。但是很少這么玩- 查看當前進程的命令:adb shell ps | grep com.gjg.text
- 進程名以":"開頭的進程屬于應用的私有進程,其它應用的組件不可以和它泡在同一個進程中秋度,非":"開頭的進程屬于全局進程炸庞,其它應用可以要通過ShareUID方式(ShareUID相同且簽名相同)和它跑在同一個進程中谨设。
2.2 多進程模式運行機制
不同的進程有獨立的虛擬機宜雀,Applicaition以及內(nèi)存空間简软,所以開啟了多進程模式的應用應注意一下問題:
1 靜態(tài)成員和單利模式完全失效
2 線程同步機制完全失效
3 SharedPreferences的可靠性下降
4 Application會多次創(chuàng)建
3 IPC基礎載體
3.1 Serializable
- serialVersionUID:用來輔助序列化和反序列化過程的璧亮,原則上序列化后的數(shù)據(jù)中的serialVersionUID只有和當前類的serialVersionUID相同才能夠被正常的反序列化交惯。
- 系統(tǒng)默認用hash值作為serialVersionUID,當變量數(shù)和類型改變時溃睹,hash會變化拌阴,所以系統(tǒng)默認情況下這種改變發(fā)生時反序列化會crash
public class User implements Serializable{
}
//序列化過程
User user = new User();
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("cache.txt"));
out.writeObject(user);
out.close();
//反序列化過程
ObjectInputStream in = new ObjectInputStream(new FileInputStream("cache.txt"));
User user = (User)in.readObject();
in.close();
3.2 Parcelable
public class User implements Parcelable{
private String name;
private int age;
public User() {
}
public User(String name, int age) {
this.name = name;
this.age = age;
}
//反序列化
protected User(Parcel in) {
name = in.readString();
age = in.readInt();
}
//用于反序列化的創(chuàng)建器
public static final Creator<User> CREATOR = new Creator<User>() {
//從序列化的數(shù)據(jù)中創(chuàng)建原始對象
@Override
public User createFromParcel(Parcel in) {
return new User(in);
}
//創(chuàng)建指定長度的原始對象數(shù)組
@Override
public User[] newArray(int size) {
return new User[size];
}
};
/**
* 返回當前對象的內(nèi)容描述
* 如果含有文件描述符朽们,返回1(CONTENTS_FILE_DESCRIPTOR)兽泣,否則返回0
* 多數(shù)都返回0
* @return
*/
@Override
public int describeContents() {
return 0;
}
/**
* 序列化操作
* @param dest
* @param flags
* 當為1(PARCELABLE_WRITE_RETURN_VALUE) 標示當前對象需要作為返回值返回绎橘,不能立即釋放資源
* 幾乎所有情況都為0
*/
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(name);
dest.writeInt(age);
}
/**
* Parcel
* 內(nèi)部包裝了可序列化的數(shù)據(jù)的native操作,例如
* @FastNative
* private static native void nativeWriteInt(long nativePtr, int val);
* @FastNative
* private static native void nativeWriteLong(long nativePtr, long val);
*/
}
- Serializabble 是java中的序列化接口唠倦,使用簡單但開銷大称鳞,序列化和反序列化過程需要大量IO操作,適用于序列化到設備或者網(wǎng)絡傳輸中
- Parcelable 是android 中的序列化方式稠鼻,使用麻煩但是效率高冈止,主要用于內(nèi)存序列化上。
3.3 Binder
(1)Binder 繼承在IBinder候齿。是IPC的框進程通訊方式
(2)還可以理解為一種虛擬的物理設備
(3)從android framework層來說Binder是ServiceManager連接各種Manager(ActivityManager WindowManager)和響應ManagerService的橋梁熙暴。
(4)從android 應用層來說是客戶端和服務端進行通訊的媒介。當bindService時慌盯,返回段會返回一個包含服務端業(yè)務調(diào)用的Binder對象周霉。
AIDL創(chuàng)建及核心源碼解析
創(chuàng)建AIDL文件
//1.創(chuàng)建User.java 同上
//2.創(chuàng)建User在AIDL中的聲明文件 User.aidl
package gjg.com.fundemo.dbg;
parcelable User;
//3.創(chuàng)建User的管理aidl文件
package gjg.com.fundemo.dbg;
//這里要注意使用全包名,且User有對應的User.aidl文件亚皂,否則會提示找不到
//aidl只支持方法生命俱箱,不支持靜態(tài)變量
import gjg.com.fundemo.dbg.User;
interface IUserManager {
List<User> getUserList();
/**
* in 輸入型參數(shù)
* out 輸出型參數(shù)
* inout 輸入輸出型參數(shù)
*/
void addUser(in User user);
}
//4.重新編譯后系統(tǒng)會生成IUserManager.java
package gjg.com.fundemo.dbg;
public interface IUserManager extends android.os.IInterface {
/**
* 集成Binder 實現(xiàn)了IUserManager接口本身
* 這是個抽象方法,并沒有實現(xiàn)IUserManager具體方法孕讳,需要在服務端自定義Binder時實現(xiàn)
* 一般在服務端繼承自改抽象類匠楚,并在onBind中返回其實現(xiàn)
*/
public static abstract class Stub extends android.os.Binder implements gjg.com.fundemo.dbg.IUserManager {
//Binder的唯一標示
private static final java.lang.String DESCRIPTOR = "gjg.com.fundemo.dbg.IUserManager";
public Stub() {
this.attachInterface(this, DESCRIPTOR);
}
/**
* 用于將服務端的Binder對象轉(zhuǎn)換成客戶端所需的AIDL接口類型的對象
*/
public static gjg.com.fundemo.dbg.IUserManager asInterface(android.os.IBinder obj) {
if ((obj == null)) {
return null;
}
//如果客戶端和服務端在同一進程,返回的就是服務端的Stub對象本身Stub.Proxy對象
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin != null) && (iin instanceof gjg.com.fundemo.dbg.IUserManager))) {
return ((gjg.com.fundemo.dbg.IUserManager) iin);
}
//如果客戶端和服務端不在同一進程厂财,返回的是封裝后的
return new gjg.com.fundemo.dbg.IUserManager.Stub.Proxy(obj);
}
/**
* 用于返回當前Binder對象芋簿,在IInterface中定義的
*/
@Override
public android.os.IBinder asBinder() {
return this;
}
/**
* 該方法運行在服務端中Binder線程池中
* 當客戶端發(fā)起請求時,遠程請求會通過系統(tǒng)底層封裝后交由此方法來處理
* 只有跨進程時才會調(diào)用此方法
* @param code
* 服務端通過code可以確定所請求的目標方法
* @param data
* data中存有目標方法所需的參數(shù)
* @param reply
* 當目標方法執(zhí)行完后會將返回值寫入reply中
* @param flags
* @return 返回false 證明客戶端請求失敗
* @throws android.os.RemoteException
*/
@Override
public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException {
switch (code) {
case INTERFACE_TRANSACTION: {
reply.writeString(DESCRIPTOR);
return true;
}
case TRANSACTION_getUserList: {
data.enforceInterface(DESCRIPTOR);
//調(diào)用服務端方法得到返回值
java.util.List<gjg.com.fundemo.dbg.User> _result = this.getUserList();
reply.writeNoException();
//返回值寫入reply
reply.writeTypedList(_result);
return true;
}
case TRANSACTION_addUser: {
data.enforceInterface(DESCRIPTOR);
gjg.com.fundemo.dbg.User _arg0;
if ((0 != data.readInt())) {
_arg0 = gjg.com.fundemo.dbg.User.CREATOR.createFromParcel(data);
} else {
_arg0 = null;
}
//調(diào)用服務端方法得到返回值
this.addUser(_arg0);
reply.writeNoException();
return true;
}
}
return super.onTransact(code, data, reply, flags);
}
/**
* 如果是跨進程通訊璃饱,該代理會被返回
*/
private static class Proxy implements gjg.com.fundemo.dbg.IUserManager {
//這個mRemote就是服務端繼承自Stub的Binder對象
private android.os.IBinder mRemote;
Proxy(android.os.IBinder remote) {
mRemote = remote;
}
@Override
public android.os.IBinder asBinder() {
return mRemote;
}
public java.lang.String getInterfaceDescriptor() {
return DESCRIPTOR;
}
//在客戶端調(diào)用与斤,最終會通過transact調(diào)服務端方法
@Override
public java.util.List<gjg.com.fundemo.dbg.User> getUserList() throws android.os.RemoteException {
//創(chuàng)建所需的輸入型Parcel對象
android.os.Parcel _data = android.os.Parcel.obtain();
//創(chuàng)建輸出型Parcel對象
android.os.Parcel _reply = android.os.Parcel.obtain();
//創(chuàng)建返回值對象
java.util.List<gjg.com.fundemo.dbg.User> _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
//發(fā)起RPC(遠程過程調(diào)用)請求,同時當前線程掛起
//transact被調(diào)用,知道RPC過程返回后撩穿,當前線程繼續(xù)執(zhí)行
//從reply中取出RPC過程的返回結(jié)果
mRemote.transact(Stub.TRANSACTION_getUserList, _data, _reply, 0);
_reply.readException();
//返回reply中的結(jié)果磷支,反序列化,這里可以看出AIDL的對象需要細線parcelable接口
_result = _reply.createTypedArrayList(gjg.com.fundemo.dbg.User.CREATOR);
} finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
@Override
public void addUser(gjg.com.fundemo.dbg.User user) throws android.os.RemoteException {
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
try {
_data.writeInterfaceToken(DESCRIPTOR);
if ((user != null)) {
_data.writeInt(1);
//將參數(shù)寫入輸出型parcel對象中
user.writeToParcel(_data, 0);
} else {
_data.writeInt(0);
}
mRemote.transact(Stub.TRANSACTION_addUser, _data, _reply, 0);
_reply.readException();
} finally {
_reply.recycle();
_data.recycle();
}
}
}
static final int TRANSACTION_getUserList = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
static final int TRANSACTION_addUser = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
}
//接口的方法定義
public java.util.List<gjg.com.fundemo.dbg.User> getUserList() throws android.os.RemoteException;
//接口的方法定義
public void addUser(gjg.com.fundemo.dbg.User user) throws android.os.RemoteException;
}
// 5.給Binder設置死亡代理
// 當服務端Binder連接斷裂時食寡,客戶端可以收到通知雾狈,一遍再次發(fā)起請求從而恢復連接的解決方案
//示例代碼如下
//服務端Service
public class UserRemoteService extends Service {
@Nullable
@Override
public IBinder onBind(Intent intent) {
return binder;
}
//返回個客戶端的Binder
IUserManager.Stub binder = new IUserManager.Stub() {
@Override
public List<User> getUserList() throws RemoteException {
return null;
}
@Override
public void addUser(User user) throws RemoteException {
}
};
}
public class UserTestActivity extends AppCompatActivity {
//客戶端對IUserManager
private IUserManager mUserManager;
//服務端Binder死亡代理對象
private DeathRecipient mDeathRecipient = new DeathRecipient();
private ServiceConnection mSc = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
//根據(jù)服務端Binder創(chuàng)建客戶端IUserManager對象
mUserManager = IUserManager.Stub.asInterface(service);
try {
//綁定服務端Binder死亡代理
service.linkToDeath(mDeathRecipient,0);
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Intent intent = new Intent(this,UserRemoteService.class);
//綁定服務
bindService(intent,mSc,0);
if(mUserManager != null){
try {
List<User> users = mUserManager.getUserList();
} catch (RemoteException e) {
e.printStackTrace();
}
}
}
/**
* Binder死亡代理
* 一般在bindService中Connection后創(chuàng)建并設置
* IUserManager mServiceBinder = IUserManager.Stub.asInterface(binder);
* binder.linkToDeath(this,0);
*/
public class DeathRecipient implements IBinder.DeathRecipient {
//當Binder死亡是會回調(diào)此方法
@Override
public void binderDied() {
if(mUserManager == null){
return;
}
//解綁服務端Binder死亡代理對象
mUserManager.asBinder().unlinkToDeath(this,0);
mUserManager = null;
}
}
}
4 Android中的IPC方式
4.1 Bundle
Bundle implements Parcelable 所以可以方便的在不同進程進行通訊
4.2 使用文件共享
適合同步要求不高的進程間通訊
4.3 Messenger
是對AIDL的簡單封裝,以Message作為載體
4.4 AIDL
流程:
-->服務端創(chuàng)建AIDL文件抵皱,編譯生成接口善榛,服務端實現(xiàn)接口的.Stub返回
-->客戶端綁定Service,綁定成功后呻畸,將服務端返回的Binder對象轉(zhuǎn)成AIDL文件對應的接口對象
注意:
aidl文件中不是所有類型都支持移盆,支持的類型如下:基本數(shù)據(jù)類型
String CharSequence
List-ArrayList,里面的每個元素必須被aidl支持,這里指服務端最終會返回ArrayList類型
Map-HashMap伤为,里面的每個元素必須被aidl支持
Parcelable咒循,所有實現(xiàn)了Parcelable接口的對象
AIDL:所有aidl接庫本身也可以在aidl文件中使用
自定義的Parcelable對象,在aidl中使用時绞愚,必須新建一個和它同名的AIDL文件叙甸,并在其中生命它為parcleable類型。例如:
package com.gjg
parcelable User;
RemoteCallbackList
- 跨進程傳輸對象的最想都會經(jīng)過反序列化位衩,也就是說兩端針對相同內(nèi)容的對象卻不是真正的同一個對象蚁署,所以就會導致跨進程解注冊時會出現(xiàn)問題,而RemoteCallbackList就為解決此問題而生蚂四。
- RemoteCallbackList是專門提供的用于刪除款進程listener的接口,它是一個泛型哪痰,支持管理任意的aidl接口,其聲明如下:
public class RemoteCallbackList<E extends IInterface>
其本質(zhì)就是利用了跨進程對象的相同對象在兩端擁有相同的底層Binder對象
安全驗證遂赠,在androidMenifest中聲明,可在服務端onBind或者onTransact中進行驗證是否有權(quán)限
4.5 ContentProvider
- 底層也是Binder機制
- 六個方法 onCreate() getType() CRUD
- CRUD 在Binder線程池
- android:authorities 聲明 ContentResolver中Uri參數(shù)與之配對
- UriMatcher 實現(xiàn)外界訪問的匹配功能
4.6 Socket
通過網(wǎng)絡了晌杰。不光能跨進程跷睦,還能跨設備
5 Binder連接池
- 背景有很多aidl時不可能對應創(chuàng)建很多Service
- Binder連接池的作用就是將每個業(yè)務模塊的Binder請求統(tǒng)一轉(zhuǎn)發(fā)到遠程的Service中去執(zhí)行,從而避免重復創(chuàng)建Service的過程
//1. 創(chuàng)建兩個簡單aidl文件
package gjg.com.fundemo.binderchi;
interface ICompute {
int add(int a,int b);
}
package gjg.com.fundemo.binderchi;
interface ISecurityCenter {
String encrypt(String content);
String decrypt(String password);
}
//2. 創(chuàng)建aidl文件對應的實現(xiàn)
package gjg.com.fundemo.binderchi;
import android.os.RemoteException;
public class SecurityCenerImpl extends ISecurityCenter.Stub {
@Override
public String encrypt(String content) throws RemoteException {
return null;
}
@Override
public String decrypt(String password) throws RemoteException {
return null;
}
}
package gjg.com.fundemo.binderchi;
public class ComputeImpl extends ICompute.Stub {
@Override
public int add(int a, int b) throws RemoteException {
return 0;
}
}
//3. 創(chuàng)建IBinderPool的aidl文件
package gjg.com.fundemo.binderchi;
interface IBinderPool {
IBinder queryBinder(int binderCode);
}
//4. 創(chuàng)建IBinderPool的實現(xiàn)肋演,作為BinderPool的內(nèi)部類
public static class BinderPoolImpl extends IBinderPool.Stub{
@Override
public IBinder queryBinder(int binderCode) throws RemoteException {
IBinder binder = null;
switch (binderCode){
case BINDER_SECURITY_CENTER:
binder = new SecurityCenerImpl();
break;
case BINDER_COMPUTE:
binder = new ComputeImpl();
break;
}
return binder;
}
}
//5. 創(chuàng)建Binder連接池的Service
public class BinderPoolService extends Service {
private BinderPool.BinderPoolImpl mBinderPoolImpl = new BinderPool.BinderPoolImpl();
@Nullable
@Override
public IBinder onBind(Intent intent) {
//返回的是服務端的BinderPoolImpl
return mBinderPoolImpl;
}
}
// 6. 創(chuàng)建BinderPool
public class BinderPool {
public static final int BINDER_SECURITY_CENTER = 1;
public static final int BINDER_COMPUTE = 2;
private Context mContext;
private IBinderPool mBinderPool;
private static volatile BinderPool sInstance;
private CountDownLatch mCountDownLatch;//用于保證線程同步
private BinderPool(Context context){
this.mContext = context;
connectBinderPoolService();
}
public static BinderPool getsInstance(Context context){
if(sInstance == null){
synchronized (BinderPool.class){
sInstance = new BinderPool(context);
}
}
return sInstance;
}
public IBinder queryBinder(int binderCode){
IBinder iBinder = null;
if(mBinderPool != null){
try {
mBinderPool.queryBinder(binderCode);
} catch (RemoteException e) {
e.printStackTrace();
}
}
return iBinder;
}
private void connectBinderPoolService() {
mCountDownLatch = new CountDownLatch(1);
Intent service = new Intent(mContext,BinderPoolService.class);
mContext.bindService(service,mBinderPoolConnection,Context.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();
}
mCountDownLatch.countDown();
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
/**
* Binder死亡監(jiān)控
*/
private IBinder.DeathRecipient mBinderPoolDeathRecipient = new IBinder.DeathRecipient() {
@Override
public void binderDied() {
mBinderPool.asBinder().unlinkToDeath(mBinderPoolDeathRecipient,0);
mBinderPool = null;
connectBinderPoolService();
}
};
public static class BinderPoolImpl extends IBinderPool.Stub{
@Override
public IBinder queryBinder(int binderCode) throws RemoteException {
IBinder binder = null;
switch (binderCode){
case BINDER_SECURITY_CENTER:
binder = new SecurityCenerImpl();
break;
case BINDER_COMPUTE:
binder = new ComputeImpl();
break;
}
return binder;
}
}
}
// 7. 使用
public class BinderPoolTestActivity extends AppCompatActivity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
doWork();
}
private void doWork() {
BinderPool binderPool = BinderPool.getsInstance(this.getApplicationContext());
IBinder securityCenterBinder = binderPool.queryBinder(BinderPool.BINDER_SECURITY_CENTER);
ISecurityCenter securityCenter = SecurityCenerImpl.asInterface(securityCenterBinder);
try {
securityCenter.encrypt("");
} catch (RemoteException e) {
e.printStackTrace();
}
IBinder computeBinder = binderPool.queryBinder(BinderPool.BINDER_COMPUTE);
ICompute compute = ComputeImpl.asInterface(computeBinder);
try {
compute.add(1,2);
} catch (RemoteException e) {
e.printStackTrace();
}
}
}