1.定義
我們都知道,Android應(yīng)用一旦啟動(dòng)就會生成一個(gè)以包名為名字的進(jìn)程,當(dāng)然我們還知道android中很多manager都是運(yùn)行在system server進(jìn)程中的,像AMS,PMS,WMS等,它們都是通過binder來進(jìn)程遠(yuǎn)程調(diào)用,說到這就不得不說多進(jìn)程之間的通信問題,進(jìn)程不像線程那樣,多線程可以共享內(nèi)存,而每個(gè)進(jìn)程的內(nèi)存都是獨(dú)立的,無法直接訪問,因此安卓提供了binder來進(jìn)行進(jìn)程間的通信。
在使用binder的過程中,android定義了一些更方便的進(jìn)程間通信的方式,像AIDL,Messenger等方式,今天我們不討論binder的原理,先來學(xué)習(xí)一下AIDL和Messenger的基本使用,廢話不多說,咱們切入正題。
2.AIDL在Android中的使用
AIDL的英文名叫做:Android Interface Definition Language,意思就是Android接口定義語言,它是用于定義服務(wù)器和客戶端通信接口的一種描述語言,可以用它來生成IPC的代碼,那么什么時(shí)候我們才需要用到AIDL呢,雖然表面上來說是進(jìn)程間通信就可以用,但是上面我們還提到了Messenger,它們分別適合什么場景呢?
只有允許不同應(yīng)用的客戶端用 IPC 方式訪問服務(wù),并且想要在服務(wù)中處理多線程時(shí),才有必要使用 AIDL。如果不需要執(zhí)行跨越不同應(yīng)用的并發(fā)IPC,就應(yīng)該通過實(shí)現(xiàn)一個(gè)Binder創(chuàng)建接口;或者如果想執(zhí)行IPC,但根本不需要處理多線程,則使用Messenger類來實(shí)現(xiàn)接口。
下面我們來看下AIDL的使用方式:
服務(wù)端代碼
首先我們定義一個(gè)場景,比如我們想獲取遠(yuǎn)程進(jìn)程的school名字和school列表,那我們就可以在遠(yuǎn)程進(jìn)程中也就是我們所說的服務(wù)端定義aidl文件,首先我們先定一個(gè)School實(shí)體類:
public class School implements Parcelable {
private String schoolName;
private String address;
public School(String schoolName, String address) {
this.schoolName = schoolName;
this.address = address;
}
protected School(Parcel in) {
schoolName = in.readString();
address = in.readString();
}
public static final Creator<School> CREATOR = new Creator<School>() {
@Override
public School createFromParcel(Parcel in) {
return new School(in);
}
@Override
public School[] newArray(int size) {
return new School[size];
}
};
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(schoolName);
dest.writeString(address);
}
public void readFromParcel(Parcel dest) {
schoolName=dest.readString();
address=dest.readString();
}
public String getSchoolName() {
return schoolName;
}
public void setSchoolName(String schoolName) {
this.schoolName = schoolName;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
}
注意這里一定要實(shí)現(xiàn)Parcelable接口,因?yàn)閍idl傳遞對象要求必須要序列化對象,android studio工具不會提示readFromParcel方法,我們自己記得加上,然后我們給對象定義一個(gè)aidl文件,即School.aidl:
// ISchool.aidl
package com.wangkeke.aidldemo;
import com.wangkeke.aidldemo.School;
// Declare any non-default types here with import statements
parcelable School;
注意這里的parcelable首字母要小寫,import需要把School類導(dǎo)入,然后我們再定義上面所說的獲取學(xué)校名字,列表等功能的aidl文件,即SchoolControllerAIDL.aidl:
package com.wangkeke.aidldemo;
import com.wangkeke.aidldemo.School;
interface SchoolControllerAIDL {
String getSchoolName(String schoolNo);
List<School> getSchools();
}
同樣要注意導(dǎo)入相應(yīng)的包,接下來我們clean一下項(xiàng)目,就會在如下目錄下生成對應(yīng)的SchoolControllerAIDL類:

aidl文件創(chuàng)建好了,當(dāng)要想和遠(yuǎn)程進(jìn)程交互,還需要借助service來bind遠(yuǎn)程服務(wù),下面我們創(chuàng)建一個(gè)AidlService:
public class AidlService extends Service {
private List<School> getSchoolLists(){
List<School> schoolList = new ArrayList<>();
schoolList.add(new School("清華大學(xué)","北京"));
schoolList.add(new School("北京大學(xué)","北京"));
schoolList.add(new School("南京大學(xué)","南京"));
schoolList.add(new School("上海復(fù)旦大學(xué)","上海"));
return schoolList;
}
SchoolControllerAIDL.Stub mBinder = new SchoolControllerAIDL.Stub() {
@Override
public String getSchoolName(String schoolNo) throws RemoteException {
return "服務(wù)器端的schoolname:清華大學(xué)";
}
@Override
public List<School> getSchools() throws RemoteException {
return getSchoolLists();
}
};
@Nullable
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
}
代碼很簡單,就是通過上面自動(dòng)生成的SchoolControllerAIDL類的Stub內(nèi)部類來創(chuàng)建一個(gè)binder對象,把它作為service中onBind方法的返回值即可,記得在AndroidManifest文件中定義:
<service android:name=".AidlService" />
客戶端代碼
下面我們就可以編寫客戶端的代碼了,我們都知道bindService需要傳遞一個(gè)ServiceConnection對象,我們來定義一下:
private ServiceConnection mConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
isConnection = true;
schoolAIDL = SchoolControllerAIDL.Stub.asInterface(service);
try {
schoolAIDL.registerListener(lisener);
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
isConnection = false;
}
};
然后在onCreate中bind服務(wù):
Intent intent = new Intent(this,AidlService.class);
bindService(intent, mConnection ,Context.BIND_AUTO_CREATE);
一旦執(zhí)行上面的bindService代碼,ServiceConnection中的onServiceConnected方法就會被調(diào)用,此時(shí)表明ServiceConnection已經(jīng)連接成功,客戶端可以訪問服務(wù)端的方法了,現(xiàn)在我們調(diào)用一下之前獲取學(xué)校和學(xué)校列表的方法試試:
btnRemote.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if(null != schoolAIDL){
try {
String schoolName = schoolAIDL.getSchoolName("STU1002");
Toast.makeText(ThirdProcessActivity.this, ""+schoolName, Toast.LENGTH_SHORT).show();
List<School> listSchools = schoolAIDL.getSchools();
StringBuilder sb = new StringBuilder();
for (int i = 0; i < listSchools.size(); i++) {
sb.append("學(xué)校名字:"+listSchools.get(i).getSchoolName()+" 學(xué)校地址:"+listSchools.get(i).getAddress()+"\n");
}
tvShow.setText(sb.toString());
} catch (RemoteException e) {
e.printStackTrace();
}
}
}
});
運(yùn)行結(jié)果如下:

注意:我們上面的例子并沒有在兩個(gè)應(yīng)用中模擬進(jìn)程間通信,而是在同一app中,只是跳轉(zhuǎn)的activity配置了process屬性,讓activity運(yùn)行在了新進(jìn)程中,實(shí)際上和不同應(yīng)用的進(jìn)程間通信是一個(gè)意思。
<activity android:name=".ThirdProcessActivity"
android:process=":other"
/>
另外還要注意如果新啟動(dòng)的activity運(yùn)行在新進(jìn)程中,那么Application會在新啟動(dòng)Activity的適合再次調(diào)用,我們來驗(yàn)證一下這個(gè)結(jié)論,修改下application中的代碼:
public class MyApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
int pid = android.os.Process.myPid();
Log.e("wangkeke", "MyApplication is oncreate====="+"pid="+pid);
String processNameString = "";
ActivityManager mActivityManager = (ActivityManager)this.getSystemService(getApplicationContext().ACTIVITY_SERVICE);
for (ActivityManager.RunningAppProcessInfo appProcess : mActivityManager.getRunningAppProcesses()) {
if (appProcess.pid == pid) {
processNameString = appProcess.processName;
}
}
if("com.wangkeke.aidldemo".equals(processNameString)){
Log.e("wangkeke", "當(dāng)前進(jìn)程為:"+processNameString+"-----主進(jìn)程(服務(wù)端進(jìn)程)");
}else{
Log.e("wangkeke", "當(dāng)前進(jìn)程為:"+processNameString+"-----clent進(jìn)程(客戶端進(jìn)程)");
}
}
}
然后我們運(yùn)行并且跳轉(zhuǎn)新進(jìn)程activity,結(jié)果如下:

正如我們預(yù)料的那樣,application確實(shí)執(zhí)行了兩次,不過解決方式也正如上面打印的日志那樣,根據(jù)進(jìn)程名判斷當(dāng)前執(zhí)行的是哪一個(gè)Application,進(jìn)行相應(yīng)的處理即可。
插播一條:服務(wù)端和客戶端進(jìn)行遠(yuǎn)程通信,傳遞的數(shù)據(jù)必須是aidl支持的,aidl支持如下數(shù)據(jù)類型:基本數(shù)據(jù)類型,String,CharSequence,List,Map(集合中的所有元素必須是aidl支持的類型),實(shí)現(xiàn)了Parcelable接口的對象。
雖然我們上面實(shí)現(xiàn)了客戶端和服務(wù)端的通信,但是大家可能也發(fā)現(xiàn)了,這tm也太簡單了吧,調(diào)用個(gè)方法就完事了,我客戶端想要回調(diào)怎么辦呢,各位別著急,android自然也是提供了客戶端回調(diào)的處理類,RemoteCallbackList類,在AIDL中客戶端向服務(wù)端注冊一個(gè)回調(diào)方法時(shí),服務(wù)端要考慮客戶端是否意外退出(客戶端因?yàn)殄e(cuò)誤應(yīng)用Crash,或者被Kill掉了),服務(wù)端還不知道,此時(shí)去回調(diào)客戶端,出現(xiàn)錯(cuò)誤。
那么該如何使用呢,其實(shí)也很簡單,我們在上面的例子中稍微改動(dòng)下,首先我們在服務(wù)端定義一個(gè)OnConnectSuccessLisener.aidl,它用來告知服務(wù)端的連接狀態(tài),并提供一個(gè)像客戶端發(fā)送數(shù)據(jù)的方法:
// OnConnectSuccessLisener.aidl
package com.wangkeke.aidldemo;
// Declare any non-default types here with import statements
interface OnConnectSuccessLisener {
void onServiceConnected();
void onServiceDisConnected();
void sendMsgToClient(String msg);
}
然后我們修改下SchoolControllerAIDL.aidl類,增加注冊回調(diào)和反注冊回調(diào)的方法:
// SchoolControllerAIDL.aidl
package com.wangkeke.aidldemo;
import com.wangkeke.aidldemo.School;
import com.wangkeke.aidldemo.OnConnectSuccessLisener;
// Declare any non-default types here with import statements
interface SchoolControllerAIDL {
String getSchoolName(String schoolNo);
List<School> getSchools();
void registerListener(OnConnectSuccessLisener listener);
void unregisterListener(OnConnectSuccessLisener listener);
}
服務(wù)端的AidlService也要稍作改動(dòng):
public class AidlService extends Service {
private RemoteCallbackList<OnConnectSuccessLisener> mListener = new RemoteCallbackList<>();
private List<School> getSchoolLists(){
List<School> schoolList = new ArrayList<>();
schoolList.add(new School("清華大學(xué)","北京"));
schoolList.add(new School("北京大學(xué)","北京"));
schoolList.add(new School("南京大學(xué)","南京"));
schoolList.add(new School("上海復(fù)旦大學(xué)","上海"));
return schoolList;
}
SchoolControllerAIDL.Stub mBinder = new SchoolControllerAIDL.Stub() {
@Override
public String getSchoolName(String schoolNo) throws RemoteException {
return "服務(wù)器端的schoolname:清華大學(xué)";
}
@Override
public List<School> getSchools() throws RemoteException {
return getSchoolLists();
}
@Override
public void registerListener(OnConnectSuccessLisener listener) throws RemoteException {
listener.onServiceConnected();
mListener.register(listener);
checkCameraState();
}
@Override
public void unregisterListener(OnConnectSuccessLisener listener) throws RemoteException {
listener.onServiceDisConnected();
mListener.unregister(listener);
}
};
private void checkCameraState() {
new Thread(new Runnable() {
@Override
public void run() {
try {
//模擬耗時(shí)任務(wù)
Thread.sleep(3000);
final int N = mListener.beginBroadcast();
for (int i = 0; i < N; i++) {
OnConnectSuccessLisener successLisener = mListener.getBroadcastItem(i);
successLisener.sendMsgToClient("我是服務(wù)端處理完耗時(shí)任務(wù)后,給客戶端發(fā)送的值");
}
mListener.finishBroadcast();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (RemoteException e) {
e.printStackTrace();
}
}
}).start();
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
}
客戶端代碼如下:
/**
* 我是客戶端
*/
public class ThirdProcessActivity extends AppCompatActivity {
private boolean isConnection = false;
private Button btnRemote;
private TextView tvShow;
OnConnectSuccessLisener lisener = new OnConnectSuccessLisener.Stub() {
@Override
public void onServiceConnected() throws RemoteException {
Log.e("wangkeke","連接成功");
}
@Override
public void onServiceDisConnected() throws RemoteException {
Log.e("wangkeke","斷開連接");
}
@Override
public void sendMsgToClient(String msg) throws RemoteException {
Log.e("wangkeke","客戶端收到消息:"+msg);
}
};
private ServiceConnection mConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
isConnection = true;
schoolAIDL = SchoolControllerAIDL.Stub.asInterface(service);
try {
schoolAIDL.registerListener(lisener);
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
isConnection = false;
}
};
private SchoolControllerAIDL schoolAIDL;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_third_process);
Intent intent = new Intent(this,AidlService.class);
bindService(intent, mConnection ,Context.BIND_AUTO_CREATE);
btnRemote = findViewById(R.id.btn_remote);
tvShow = findViewById(R.id.tv_show);
btnRemote.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if(null != schoolAIDL){
try {
String schoolName = schoolAIDL.getSchoolName("STU1002");
Toast.makeText(ThirdProcessActivity.this, ""+schoolName, Toast.LENGTH_SHORT).show();
List<School> listSchools = schoolAIDL.getSchools();
StringBuilder sb = new StringBuilder();
for (int i = 0; i < listSchools.size(); i++) {
sb.append("學(xué)校名字:"+listSchools.get(i).getSchoolName()+" 學(xué)校地址:"+listSchools.get(i).getAddress()+"\n");
}
tvShow.setText(sb.toString());
} catch (RemoteException e) {
e.printStackTrace();
}
}
}
});
}
@Override
protected void onDestroy() {
super.onDestroy();
try {
if(isConnection && schoolAIDL.asBinder().isBinderAlive()){
schoolAIDL.unregisterListener(lisener);
}
} catch (RemoteException e) {
e.printStackTrace();
}
unbindService(mConnection);
}
}
我們在bindService之后,onServiceConnected建立連接,通過registerListener方法客戶端注冊了回調(diào)方法,此時(shí)服務(wù)端接收到后會處理一個(gè)耗時(shí)任務(wù),然后通過RemoteCallbackList的register方法,把listener存儲起來,此時(shí)我們運(yùn)行,結(jié)果如下:

可以看到我們在啟動(dòng)客戶端之后,3秒后會自動(dòng)回調(diào)給客戶端數(shù)據(jù),其實(shí)到這里我們好像就可以通過存儲registerListener(OnConnectSuccessLisener listener)的參數(shù)OnConnectSuccessLisener,可以在服務(wù)端任何地方給客戶端發(fā)消息,前提是客戶端還在運(yùn)行,比如把定義一個(gè)static類型的變量把listener存起來,不過這種方式很不優(yōu)雅,不知道大家有好的方式?jīng)],歡迎留言討論(當(dāng)然也可以通過客戶端不斷的輪訓(xùn)來獲取服務(wù)端的某個(gè)狀態(tài)后再返回需要的數(shù)據(jù))。
注意:RemoteCallbackList是用于專門添加和刪除跨進(jìn)程listener的類,它內(nèi)部維護(hù)了一個(gè)mCallbacks,以客戶端和服務(wù)端建立的IBinder為key,所以添加和移除callback變得簡單明了:
ArrayMap<IBinder, Callback> mCallbacks
= new ArrayMap<IBinder, Callback>();
我們通過它的register和unregister方法來實(shí)時(shí)添加和刪除callback,保證了回調(diào)的正確性!
另外,無論是客戶端訪問服務(wù)端的方法還是服務(wù)端訪問客戶端,發(fā)起方在已知知對方是耗時(shí)操作的情況下,一定不要在主線程發(fā)起調(diào)用,因?yàn)榘l(fā)起方發(fā)起遠(yuǎn)程請求之后,當(dāng)前線程會進(jìn)入掛起狀態(tài),只有對方響應(yīng)之后才會重新恢復(fù)執(zhí)行,所以為了避免在主線程進(jìn)行耗時(shí)操作,需開啟子線程發(fā)起遠(yuǎn)程操作。
3.aidl生成代碼分析
我們來看下咱們上面的例子中根據(jù)aidl文件自動(dòng)生成的SchoolControllerAIDL類,來了解下它的實(shí)現(xiàn)原理:
public interface SchoolControllerAIDL extends android.os.IInterface {
/**
* Local-side IPC implementation stub class.
*/
public static abstract class Stub extends android.os.Binder implements com.wangkeke.aidldemo.SchoolControllerAIDL {
private static final java.lang.String DESCRIPTOR = "com.wangkeke.aidldemo.SchoolControllerAIDL";
/**
* Construct the stub at attach it to the interface.
*/
public Stub() {
this.attachInterface(this, DESCRIPTOR);
}
/**
* Cast an IBinder object into an com.wangkeke.aidldemo.SchoolControllerAIDL interface,
* generating a proxy if needed.
*/
public static com.wangkeke.aidldemo.SchoolControllerAIDL asInterface(android.os.IBinder obj) {
if ((obj == null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin != null) && (iin instanceof com.wangkeke.aidldemo.SchoolControllerAIDL))) {
return ((com.wangkeke.aidldemo.SchoolControllerAIDL) iin);
}
return new com.wangkeke.aidldemo.SchoolControllerAIDL.Stub.Proxy(obj);
}
@Override
public android.os.IBinder asBinder() {
return this;
}
@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_getSchoolName: {
data.enforceInterface(DESCRIPTOR);
java.lang.String _arg0;
_arg0 = data.readString();
java.lang.String _result = this.getSchoolName(_arg0);
reply.writeNoException();
reply.writeString(_result);
return true;
}
case TRANSACTION_getSchools: {
data.enforceInterface(DESCRIPTOR);
java.util.List<com.wangkeke.aidldemo.School> _result = this.getSchools();
reply.writeNoException();
reply.writeTypedList(_result);
return true;
}
case TRANSACTION_registerListener: {
data.enforceInterface(DESCRIPTOR);
com.wangkeke.aidldemo.OnConnectSuccessLisener _arg0;
_arg0 = com.wangkeke.aidldemo.OnConnectSuccessLisener.Stub.asInterface(data.readStrongBinder());
this.registerListener(_arg0);
reply.writeNoException();
return true;
}
case TRANSACTION_unregisterListener: {
data.enforceInterface(DESCRIPTOR);
com.wangkeke.aidldemo.OnConnectSuccessLisener _arg0;
_arg0 = com.wangkeke.aidldemo.OnConnectSuccessLisener.Stub.asInterface(data.readStrongBinder());
this.unregisterListener(_arg0);
reply.writeNoException();
return true;
}
}
return super.onTransact(code, data, reply, flags);
}
private static class Proxy implements com.wangkeke.aidldemo.SchoolControllerAIDL {
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;
}
@Override
public java.lang.String getSchoolName(java.lang.String schoolNo) throws android.os.RemoteException {
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
java.lang.String _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
_data.writeString(schoolNo);
mRemote.transact(Stub.TRANSACTION_getSchoolName, _data, _reply, 0);
_reply.readException();
_result = _reply.readString();
} finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
@Override
public java.util.List<com.wangkeke.aidldemo.School> getSchools() throws android.os.RemoteException {
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
java.util.List<com.wangkeke.aidldemo.School> _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
mRemote.transact(Stub.TRANSACTION_getSchools, _data, _reply, 0);
_reply.readException();
_result = _reply.createTypedArrayList(com.wangkeke.aidldemo.School.CREATOR);
} finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
@Override
public void registerListener(com.wangkeke.aidldemo.OnConnectSuccessLisener listener) throws android.os.RemoteException {
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
try {
_data.writeInterfaceToken(DESCRIPTOR);
_data.writeStrongBinder((((listener != null)) ? (listener.asBinder()) : (null)));
mRemote.transact(Stub.TRANSACTION_registerListener, _data, _reply, 0);
_reply.readException();
} finally {
_reply.recycle();
_data.recycle();
}
}
@Override
public void unregisterListener(com.wangkeke.aidldemo.OnConnectSuccessLisener listener) throws android.os.RemoteException {
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
try {
_data.writeInterfaceToken(DESCRIPTOR);
_data.writeStrongBinder((((listener != null)) ? (listener.asBinder()) : (null)));
mRemote.transact(Stub.TRANSACTION_unregisterListener, _data, _reply, 0);
_reply.readException();
} finally {
_reply.recycle();
_data.recycle();
}
}
}
static final int TRANSACTION_getSchoolName = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
static final int TRANSACTION_getSchools = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
static final int TRANSACTION_registerListener = (android.os.IBinder.FIRST_CALL_TRANSACTION + 2);
static final int TRANSACTION_unregisterListener = (android.os.IBinder.FIRST_CALL_TRANSACTION + 3);
}
public java.lang.String getSchoolName(java.lang.String schoolNo) throws android.os.RemoteException;
public java.util.List<com.wangkeke.aidldemo.School> getSchools() throws android.os.RemoteException;
public void registerListener(com.wangkeke.aidldemo.OnConnectSuccessLisener listener) throws android.os.RemoteException;
public void unregisterListener(com.wangkeke.aidldemo.OnConnectSuccessLisener listener) throws android.os.RemoteException;
}
可以看到SchoolControllerAIDL本身是個(gè)接口,繼承了IInterface接口,來看下IInterface的定義:
public interface IInterface
{
public IBinder asBinder();
}
我們來分別介紹一下SchoolControllerAIDL接口中幾個(gè)關(guān)鍵的方法和內(nèi)部類,首先看到定義了一個(gè)DESCRIPTOR常量,它是Binder的唯一標(biāo)識,asBinder()方法返回了當(dāng)前的binder對象,asInterface方法的作用是用于將服務(wù)端的binder對象轉(zhuǎn)化成客戶端所需的AIDL接口類型的對象,并且可以看到,如果客戶端和服務(wù)端在一個(gè)進(jìn)程,那么直接返回服務(wù)端的Stub對象本身,否則返回封裝后的Stub.Proxy代理對象;onTransact方法的作用是根據(jù)客戶端的code來判斷客戶端請求的目標(biāo)方法是什么,然后根據(jù)Parcel中的序列化數(shù)據(jù),data存儲了裝載數(shù)據(jù),接著從data中取出目標(biāo)方法所需的參數(shù),然后執(zhí)行目標(biāo)方法,之后把函數(shù)返回值寫入到reply中。
注意,如果onTransact方法返回false,客戶端會請求失敗,我們在時(shí)機(jī)應(yīng)用中肯定不希望隨便一個(gè)進(jìn)程都能夠連接我們的遠(yuǎn)程服務(wù),因此可以用onTransact的返回值的特性來做權(quán)限驗(yàn)證。
接下來看一下內(nèi)部類Proxy,它實(shí)現(xiàn)了SchoolControllerAIDL接口,它運(yùn)行在客戶端,它也有一個(gè)asBinder方法,用來返回遠(yuǎn)程binder對象,用來進(jìn)行遠(yuǎn)程調(diào)用,客戶端調(diào)用服務(wù)端的方法的時(shí)候,以getSchoolName為例,首先創(chuàng)建輸入型Parcel對象_data,輸出型Parcel對象_reply,以及返回值_result,然后把參數(shù)信息寫入到_data中,就是通過它的transact方法來執(zhí)行遠(yuǎn)程操作的,transact內(nèi)部調(diào)用了onTransact方法,注意,當(dāng)調(diào)用transact的時(shí)候,當(dāng)前線程會掛起,然后調(diào)用服務(wù)端的onTransact方法,直到onTransact執(zhí)行結(jié)束返回后,當(dāng)前線程繼續(xù)執(zhí)行,從_reply中取出執(zhí)行結(jié)果,賦值給result并返回。
圖解流程:

注意:當(dāng)客戶端發(fā)起遠(yuǎn)程請求時(shí),由于當(dāng)前線程會被掛起直到服務(wù)器進(jìn)程返回?cái)?shù)據(jù),如果遠(yuǎn)程方法很耗時(shí),那么注意不能在Ui線程發(fā)起遠(yuǎn)程請求;另外服務(wù)端的binder方法運(yùn)行在binder線程池中,耗時(shí)操作也無需開啟新線程,因?yàn)槠浔旧砭褪且粋€(gè)子線程了。
4.linkToDeath和unlinkToDeath
這倆方法是binder類比較重要的方法,因?yàn)閎inder運(yùn)行在服務(wù)端進(jìn)程中,如果服務(wù)端進(jìn)程異常終止,那么這時(shí)候binder連接就會斷開,導(dǎo)致我們的遠(yuǎn)程請求失敗,而且對于客戶端來說,并不知道binder連接已經(jīng)斷開,對于這個(gè)問題,binder提供了linkToDeath和unlinkToDeath方法來解決。
通過linkToDeath可以給binder設(shè)置一個(gè)死亡代理,當(dāng)binder死亡時(shí),就會收到通知,可以重新發(fā)起連接請求從而恢復(fù),具體用法如下:
//定義死亡代理對象
private IBinder.DeathRecipient deathRecipient = new IBinder.DeathRecipient() {
@Override
public void binderDied() {
if(null != schoolAIDL){
schoolAIDL.asBinder().unlinkToDeath(deathRecipient,0);
schoolAIDL = null;
//重新綁定service
Intent intent = new Intent(ThirdProcessActivity.this,AidlService.class);
bindService(intent, mConnection ,Context.BIND_AUTO_CREATE);
}
}
};
在ServiceConnection的onServiceConnected方法中給binder設(shè)置死亡代理:
private ServiceConnection mConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
isConnection = true;
schoolAIDL = SchoolControllerAIDL.Stub.asInterface(service);
try {
//設(shè)置死亡代理
service.linkToDeath(deathRecipient,0);
schoolAIDL.registerListener(lisener);
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
isConnection = false;
}
};
此時(shí)當(dāng)服務(wù)端死亡的時(shí)候,客戶端就會收到通知,然后就可以自己處理相應(yīng)的邏輯了。
另外關(guān)于AIDL中定向tag的in,out,inout的理解和作用,大家可以看下這篇文章,你真的理解AIDL中的in,out,inout么?
6.Messenger的使用
Messenger同樣是android提供的一種IPC通信方式,它是通過在進(jìn)程間傳遞Message對象,通過Message的setData方法,傳遞Bundle對象,Bundle傳遞的數(shù)據(jù)必須實(shí)現(xiàn)Parcelable接口,Messener是串行工作的,不存在并發(fā)問題。
其實(shí)Messenger的底層實(shí)現(xiàn)就是AIDL,通過它的構(gòu)造方法就會發(fā)現(xiàn)其中的端倪:
public Messenger(IBinder target) {
mTarget = IMessenger.Stub.asInterface(target);
}
它其實(shí)是對AIDL的封裝,讓我們不再需要編寫aidl文件,就可以實(shí)現(xiàn)進(jìn)程間通信。下面來具體看下它的用法,首先看下服務(wù)端代碼:
public class MessengerService extends Service {
public static Messenger clientMessenger;
public static final int MSG_FROM_CLIENT = 0;
public static final int MSG_FROM_SERVICE = 1;
// mServiceHandler
private static Handler mServiceHandler = new Handler(){
public void handleMessage(Message msgFromClient) {
switch (msgFromClient.what) {
case MSG_FROM_CLIENT:
//拿到客戶端發(fā)來的消息
Log.e("wangkeke", "服務(wù)器接收到的消息:"+msgFromClient.getData().getString("client_msg"));
//拿到客戶端的mClientMessenger
Messenger mClientMessenger = msgFromClient.replyTo;
clientMessenger = mClientMessenger;
Message msgFromService = Message.obtain(null,MSG_FROM_SERVICE);
Bundle bundle = new Bundle();
bundle.putString("service_msg", "這里是服務(wù)器,收到客戶端請求");
msgFromService.setData(bundle);
try {
//調(diào)用mClientMessenger.send將消息發(fā)送給客戶端
mClientMessenger.send(msgFromService);
} catch (RemoteException e) {
e.printStackTrace();
}
break;
}
};
};
// mServiceMessenger關(guān)聯(lián)mServiceHandler
private Messenger mServiceMessenger = new Messenger(mServiceHandler);
@Override
public IBinder onBind(Intent intent) {
//將IBinder傳給客戶端,客戶端通過new Messenger(IBinder)拿到mServiceMessenger;
return mServiceMessenger.getBinder();
}
}
首先創(chuàng)建一個(gè)Messenger對象mServiceMessenger,它需要一個(gè)handler作為接收客戶端消息的載體,在Service的onBind中返回服務(wù)端Messenger的getBinder()即可。
再來看下客戶端的代碼:
//客戶端用來接收服務(wù)端消息的Handler
private static Handler mClientHandler = new Handler(){
public void handleMessage(Message msgFromService) {
switch (msgFromService.what) {
case MSG_FROM_SERVICE:
Log.e("wangkeke", "客戶端:"+msgFromService.getData().getString("service_msg"));
break;
}
};
};
//客戶端Messenger對象
private Messenger mClientMessenger = new Messenger(mClientHandler);
conn = new ServiceConnection() {
@Override
public void onServiceDisconnected(ComponentName name) {
}
@Override
public void onServiceConnected(ComponentName name, IBinder iBinder) {
Log.e("wangkeke", "onServiceConnected handler 當(dāng)前進(jìn)程id:"+android.os.Process.myPid()+ " 當(dāng)前線程id:"+android.os.Process.myTid());
//拿到服務(wù)器傳給客戶端的IBinder,創(chuàng)建服務(wù)端的Messenger
mServiceMessenger = new Messenger(iBinder);
//實(shí)例化一個(gè)Message
Message msgFromClient = Message.obtain(null, MSG_FROM_CLIENT);
Bundle bundle = new Bundle();
bundle.putString("client_msg", "已經(jīng)和服務(wù)器建立連接了");
msgFromClient.setData(bundle);
//將mClientMessenger帶到服務(wù)器去
msgFromClient.replyTo = mClientMessenger;
try {
//調(diào)用mServiceMessenger.send將消息發(fā)送的服務(wù)器
mServiceMessenger.send(msgFromClient);
} catch (RemoteException e) {
e.printStackTrace();
}
}
};
//綁定Service
Intent intent = new Intent(this,MessengerService.class);
bindService(intent, conn, BIND_AUTO_CREATE);
//客戶端給服務(wù)端主動(dòng)發(fā)消息
findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//新建message對象
Message msgFromClient = Message.obtain(null,MSG_FROM_CLIENT);
//傳值
Bundle bundle = new Bundle();
bundle.putString("client_msg", "我是另一進(jìn)程的客戶端發(fā)來的消息");
msgFromClient.setData(bundle);
//把客戶端的Messenger傳遞給服務(wù)端,使用雙向通信
msgFromClient.replyTo = mClientMessenger;
try {
//通過服務(wù)端的Messenger發(fā)送消息
mServiceMessenger.send(msgFromClient);
} catch (RemoteException e) {
e.printStackTrace();
}
}
});
運(yùn)行結(jié)果如下:

可以看到使用Messenger發(fā)送消息確實(shí)很方便,而且無需我們再編寫aidl文件,通過message消息直接發(fā)送即可,但是它也有明顯的缺點(diǎn),要想服務(wù)端響應(yīng)的話,需要在客戶端也創(chuàng)建一個(gè)Messenger,通過reply傳遞到服務(wù)端。
注意點(diǎn):
1.Messenger一次只能處理一個(gè)請求(串行)/AIDL一次可以處理多個(gè)請求(并行);
2.Messenger不支持RPC,只能通過message傳遞消息/AIDL支持RPC;
3.Messenger使用簡單,輕量級,不需要?jiǎng)?chuàng)建AIDL文件/AIDL使用復(fù)雜,需要?jiǎng)?chuàng)建AIDL文件;

參考鏈接:
1.Android使用Messenger實(shí)現(xiàn)進(jìn)程間通信
2.Android開發(fā)藝術(shù)探索
3.你真的理解AIDL中的in,out,inout么?
4.Messenger與AIDL的區(qū)別、優(yōu)缺點(diǎn)