Android Binder,AIDL跨進程通訊詳解與實現(xiàn),看一遍就懂
1.說到AIDL,就會聯(lián)想到Binder機制,
Binder 是一種進程間通信機制
整個app屬于客戶端,系統(tǒng)是服務(wù)端,他們之間的通訊就是通過IPC交互,中間服務(wù)就是serviceSystem
優(yōu)點:性能,穩(wěn)定性,安全性
設(shè)計:Client/Server/ServiceManager/驅(qū)動
實現(xiàn):AIDL
二、核心代碼處
1.可以通過AndroidStudio創(chuàng)建:
1.1選中一個包進行新建一個aidl,系統(tǒng)會自動生成一個aidl的文件夾
1.2手動創(chuàng)建文件夾,創(chuàng)建包名,然后在包內(nèi)創(chuàng)建aidl文件。


1.3我們創(chuàng)建兩個AIDL文件 IMsgManager.aidl,IReceiverMsgListener

IMsgManager:消息管理類,提供消息的接口
IReceiverMsgListener:消息接收類,做轉(zhuǎn)發(fā)使用
1.4Msg是對象,aidl常見的參數(shù)只支持簡單的數(shù)據(jù)類型,對象需要通過Parcelable序列化處理。
1.4.1 先定義一個Msg 實現(xiàn) Parcelable接口,,注意這個類的包名一定要與aidl文件下的包名一致,因為我們要定義一個空的Msg.aidl文件,這樣Msg.aidl文件才會與Msg.Java文件關(guān)聯(lián)起來
Msg.aidl文件:刪除interface Msg,將Msg申明為 parcelable;

這樣就就可以了。
IMsgManager:

由于aidl文件不能關(guān)聯(lián),使用類都需要手動導入包名。
IReceiveMsgListener:

定義好AIDL文件,我們要生成對應(yīng)的java文件:點擊

將項目編譯一下,aidl文件對應(yīng)的java文件出現(xiàn)在這個下方。

這個時候有人會發(fā)現(xiàn)少了一個Msg的java文件,由于我們將Msg.aidl申明為parcelable,將會關(guān)聯(lián)Parcelable的實體,和java文件已關(guān)聯(lián)起來。

這樣,我們就可以通過aidl發(fā)送自定義對象。
2.Service的處理(C/S)
2.1我們需要創(chuàng)建一個Service,作為服務(wù)端在監(jiān)控
public class MySevice extends Service {
//AIDL不支持正常的接口回調(diào),使用RemoteCallbackList實現(xiàn)接口回調(diào)
private RemoteCallbackList mReceiveListener = new RemoteCallbackList();
@Nullable
@Override
public IBinder onBind(Intent intent) {
return new MyIBinder();
}
public class MyIBinder extends IMsgManager.Stub {
@Override
public void sendMsg(Msg msg) throws RemoteException {
receiveMsg(msg);
}
@Override
public void registerReceiveListener(IReceiveMsgListener receiveListener) throws RemoteException {
mReceiveListener.register(receiveListener);
}
@Override
public void unregisterReceiveListener(IReceiveMsgListener receiveListener) throws RemoteException {
boolean success = mReceiveListener.unregister(receiveListener);
if (success){
Log.d("tag","=== 解除注冊成功");
}else {
Log.d("tag","=== 解除注冊失敗 ");
}
}
@Override
public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
return super.onTransact(code, data, reply, flags);
}
};
//收到消息處理
public void receiveMsg(Msg msg) {
//通知Callback循環(huán)開始,返回size為實現(xiàn)mReceiveListener回調(diào)的個數(shù)
final int size = mReceiveListener.beginBroadcast();
msg.setMsg("我是服務(wù)器,我收到了:"+msg.getMsg());
for (int i = 0; i < size; i++){
IReceiveMsgListener listener = mReceiveListener.getBroadcastItem(i);
if (listener != null){
try {
listener.onReceive(msg);
} catch (RemoteException e) {
e.printStackTrace();
}
}
}
//通知通知Callback循環(huán)結(jié)束
mReceiveListener.finishBroadcast();
}
}
2.2將service注冊到AndroidManifest
三、Service與Activity之間的通訊(在當前APP內(nèi))
3.1綁定服務(wù)
IMsgManager myIBinder = null;
private TextView textView;
private Button button_1, button_2, button_3;
public static final String ACTIO_SERVICE = "com.test.aidl.action";
IMsgManager iMsgManager;
private EditText editText_1;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
}
private void initView() {
editText_1=findViewById(R.id.edit_1);
textView = findViewById(R.id.text_1);
button_1 = findViewById(R.id.btn_1);
button_2 = findViewById(R.id.btn_2);
button_3 = findViewById(R.id.btn_3);
button_1.setOnClickListener(this);
button_2.setOnClickListener(this);
button_3.setOnClickListener(this);
}
@Override
public void onClick(View v) {
if (v == button_1) {
//綁定
bindService();
} else if (v == button_2) {
//發(fā)送
try {
if (myIBinder != null) {
if (editText_1.getText().toString().isEmpty())
return;
Msg msg = new Msg("服務(wù)端發(fā)送:"+editText_1.getText());
myIBinder.sendMsg(msg);
}
} catch (RemoteException e) {
e.printStackTrace();
}
} else if (v == button_3) {
//解綁
unbindService(connection);
}
}
private void bindService() {
//注冊service
Intent intent = new Intent(this, MySevice.class);
intent.setAction(ACTIO_SERVICE);
bindService(intent, connection, Service.BIND_AUTO_CREATE);
}
//service的鏈接
private ServiceConnection connection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
myIBinder = IMsgManager.Stub.asInterface(service);
iMsgManager = IMsgManager.Stub.asInterface(service);
try {
//注冊binder連接
iMsgManager.asBinder().linkToDeath(mDeathRecipient, 0);
} catch (RemoteException e) {
e.printStackTrace();
}
try {
iMsgManager.registerReceiveListener(mReceiveMsgListener);
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
//斷開連接
}
};
private IBinder.DeathRecipient mDeathRecipient = new IBinder.DeathRecipient() {
// //當承載IBinder的進程消失時接收回調(diào)的接口
@Override
public void binderDied() {
if (null == iMsgManager) {
return;
}
//解綁
iMsgManager.asBinder().unlinkToDeath(mDeathRecipient, 0);
iMsgManager = null;
}
};
private IReceiveMsgListener mReceiveMsgListener = new IReceiveMsgListener.Stub() {
@Override
public void onReceive(Msg msg) throws RemoteException {
//消息分發(fā)
textView.append("\n" + msg.getMsg());
}
};
這樣就完成再App的消息分發(fā)
四、我們要在兩個App中實現(xiàn)消息傳遞,也就是跨進程IPC。
由于我們已完成了一個service端的開發(fā),我們在創(chuàng)建一個新的app,作為令一個進程。
4.1同樣把所service APP中的aidl復制到B的app中,Msg對象也要一同復制到對應(yīng)的包下(兩邊保持一致)

把Msg自定義的實體也復制過來。兩邊要保持包名一致。接下我們還是需要make一下項目。

執(zhí)行完,會生成一下

4.2 實現(xiàn)service的綁定,可以把A app的代碼復制過來。修改注冊service方法
IMsgManager myIBinder = null;
private TextView textView;
private Button button_1, button_2, button_3;
public static final String ACTIO_SERVICE = "com.test.aidl.action";
IMsgManager iMsgManager;
EditText edit_1;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
}
private void initView() {
edit_1=findViewById(R.id.edit_1);
textView = findViewById(R.id.text_1);
button_1 = findViewById(R.id.btn_1);
button_2 = findViewById(R.id.btn_2);
button_3 = findViewById(R.id.btn_3);
button_1.setOnClickListener(this);
button_2.setOnClickListener(this);
button_3.setOnClickListener(this);
}
@Override
public void onClick(View v) {
if (v == button_1) {
//綁定
bindService();
} else if (v == button_2) {
//接收
try {
if (myIBinder != null) {
if (edit_1.getText().toString().isEmpty())
return;
Msg msg = new Msg("客戶端發(fā)送:"+edit_1.getText());
myIBinder.sendMsg(msg);
}
} catch (RemoteException e) {
e.printStackTrace();
}
} else if (v == button_3) {
//解綁
unbindService(connection);
}
}
private void bindService() {
//綁定需要注意一下,由于我們啟動其他應(yīng)用的,需要知道包名和,filter-action
Intent intent = new Intent();
intent.setPackage("com.example.mydemoa");//包名,服務(wù)端的包名(service)
intent.setAction(ACTIO_SERVICE);//action
bindService(intent, connection, Service.BIND_AUTO_CREATE);
}
private ServiceConnection connection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
myIBinder = IMsgManager.Stub.asInterface(service);
iMsgManager = IMsgManager.Stub.asInterface(service);
try {
iMsgManager.asBinder().linkToDeath(mDeathRecipient, 0);
} catch (RemoteException e) {
e.printStackTrace();
}
try {
iMsgManager.registerReceiveListener(mReceiveMsgListener);
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
private void showUI() throws RemoteException {
}
private IBinder.DeathRecipient mDeathRecipient = new IBinder.DeathRecipient() {
// //當承載IBinder的進程消失時接收回調(diào)的接口
@Override
public void binderDied() {
if (null == iMsgManager) {
return;
}
iMsgManager.asBinder().unlinkToDeath(mDeathRecipient, 0);
iMsgManager = null;
}
};
private IReceiveMsgListener mReceiveMsgListener = new IReceiveMsgListener.Stub() {
@Override
public void onReceive(Msg msg) throws RemoteException {
msg.setTime(System.currentTimeMillis());
textView.append("\n" + msg.getMsg());
}
};
4.4這樣基本完成,接下來開始測試。測試先啟動service的app。然后在打開b的,否則B打開,service沒有啟動,導致消息無法傳遞
五、結(jié)果:


這樣就完成了跨進程消息傳遞
注意:關(guān)于自定義對象,是先創(chuàng)建一個實體對象,實現(xiàn)Parcelable接口,再在aidl文件夾下的包內(nèi)創(chuàng)建一個aidl文件名為java一樣的。同事包名也一樣,刪除aidl文件內(nèi)接口代碼行,
interface Msg{
/**
* Demonstrates some basic types that you can use as parameters
* and return values in AIDL.
*/
}
然后改成申明為:parcelable Msg;即可。不然會報錯。網(wǎng)上大多數(shù)教程都沒有交會如何關(guān)聯(lián)自定義java文件與aidl文件。
*************************************************************************************************************
很感謝官方,今天剛整理好,就推上了領(lǐng)域內(nèi)容熱榜第八名。以后將會寫出更好的博客回饋大家。

本文僅代表作者觀點,版權(quán)歸原創(chuàng)者所有,如需轉(zhuǎn)載請在文中注明來源及作者名字。
免責聲明:本文系轉(zhuǎn)載編輯文章,僅作分享之用。如分享內(nèi)容、圖片侵犯到您的版權(quán)或非授權(quán)發(fā)布,請及時與我們聯(lián)系進行審核處理或刪除,您可以發(fā)送材料至郵箱:service@tojoy.com






