Android基于Aidl的跨進(jìn)程間雙向通信管理中心
得益于最近有點(diǎn)時間和精力,我想起來了一件事。那就是在上家公司,公司要求做一個APP進(jìn)程間的通信的功能,并不是APP對APP的直接跨進(jìn)程通信,而是通過一個服務(wù)中心,做接收,然后,再轉(zhuǎn)發(fā),避免應(yīng)用之間耦合性高,不然的話,新增一個APP,其他APP也要進(jìn)行升級更新(類似于有服務(wù)中心的聊天室)。
我就花幾個小時寫點(diǎn)東西吧,順便記錄一下
大家都知道在Android設(shè)備上,有很多方式,比如,廣播,socket,共享內(nèi)存,aidl等,其中廣播和aidl都是基于android中iBinder機(jī)制
廣播:
廣播有缺陷,就是效率不高,有時候會遇到廣播丟失,或者說廣播的隊(duì)列過長,導(dǎo)致消息發(fā)送慢;
共享內(nèi)存:
共享內(nèi)存沒有安全性可言,而且多線程讀寫數(shù)據(jù)的話,會無法控制
socket:
socket耦合度較高,內(nèi)存需要拷貝兩次,適用于跨網(wǎng)絡(luò)
AIDL:
基于binder,效率高;基于C/S架構(gòu),分層清晰,功能明確;有Linux的進(jìn)程ID概念,更加安全等優(yōu)點(diǎn)
流程圖

很簡單的架構(gòu),所有的APP消息傳遞都通過Server來做,工程結(jié)構(gòu)如下,center(消息中心),app1,app2都依賴于lib(aidl接口庫)

利用aidl中的RemoteCallbackList類(原理和源碼我就不多說了,其實(shí)Client調(diào)用Server是大同小異的,只不過是反者來了一次),來實(shí)現(xiàn)client中的接口回調(diào),這樣才能從server主動給client發(fā)消息,一般我們都是client主動調(diào)用Server,現(xiàn)在輪到Server主動調(diào)用client
服務(wù)端的代碼如下,你可以按照你項(xiàng)目的要求來做
package com.helang.messagecenterdemo;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.support.annotation.Nullable;
import android.util.Log;
import com.helang.lib.IMyAidlCallBackInterface;
import com.helang.lib.IMyAidlInterface;
/**
* 消息服務(wù)中心(記得在 manifest.xml 加上 android:exported="true")
*/
public class MyService extends Service {
private final static String TAG = MyService.class.getSimpleName();
private RemoteCallbackList<IMyAidlCallBackInterface> callbackList = new RemoteCallbackList<>();//回調(diào)的關(guān)鍵(API>=17,才能使用)
@Override
public void onCreate() {
super.onCreate();
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
return iBinder;
}
/**
* 實(shí)現(xiàn)iBinder
*/
private IMyAidlInterface.Stub iBinder = new IMyAidlInterface.Stub() {
@Override
public void sendMessage(String tag, String message) throws RemoteException {
callbackList.beginBroadcast();
sendMessageToAllClient(tag,message);
Log.d(TAG,"tag="+tag+" message="+message);
callbackList.finishBroadcast();
}
@Override
public void registerListener(IMyAidlCallBackInterface listener) throws RemoteException {
callbackList.register(listener);//注冊回調(diào)listener
Log.d(TAG,"registerListener");
}
@Override
public void unregisterListener(IMyAidlCallBackInterface listener) throws RemoteException {
callbackList.unregister(listener);//取消回調(diào)listener
Log.d(TAG,"unregisterListener");
}
};
/**
* 發(fā)送消息給全部的client(你也可以指定發(fā)送給某個client,也可
* 以根據(jù)自己的業(yè)務(wù)來封裝一下Bean,記得要實(shí)現(xiàn)Parcelable接口來序列化
* @param tag
* @param message
*/
private void sendMessageToAllClient(String tag,String message){
for (int i = 0 ; i < callbackList.getRegisteredCallbackCount();i++){
try {
callbackList.getBroadcastItem(i).callback(tag,message);
} catch (RemoteException e) {
e.printStackTrace();
}
}
}
}
Client1和Client2代碼是一樣的,就是相互發(fā)消息:
package com.helang.app2;
import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Handler;
import android.os.IBinder;
import android.os.RemoteException;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import com.helang.lib.IMyAidlCallBackInterface;
import com.helang.lib.IMyAidlInterface;
public class MainActivity extends AppCompatActivity {
private EditText editText;
private Button bt_send;
private TextView text;
private IMyAidlInterface iMyAidlInterface;
private ServiceCallBack serviceCallBack;
private MyServiceConnection myServiceConnection;
private Handler handler = new Handler();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
bt_send = findViewById(R.id.bt_send);
editText = findViewById(R.id.editText);
text = findViewById(R.id.text);
bt_send.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (iMyAidlInterface != null){
try {
iMyAidlInterface.sendMessage("app2",editText.getText().toString().trim());
} catch (RemoteException e) {
e.printStackTrace();
}
}
}
});
bindService();
}
@Override
protected void onDestroy() {
super.onDestroy();
unbindService();
}
private void bindService(){
myServiceConnection = new MyServiceConnection();
serviceCallBack = new ServiceCallBack();
Intent intent = new Intent();
intent.setComponent(new ComponentName("com.helang.messagecenterdemo",
"com.helang.messagecenterdemo.MyService"));
startService(intent);//開啟遠(yuǎn)程服務(wù)
bindService(intent,myServiceConnection,BIND_AUTO_CREATE);//綁定服務(wù)
}
private void unbindService(){
if (myServiceConnection != null){
try {
iMyAidlInterface.unregisterListener(serviceCallBack);
} catch (RemoteException e) {
e.printStackTrace();
}
unbindService(myServiceConnection);
}
}
/**
* 連接Service
*/
class MyServiceConnection implements ServiceConnection {
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
iMyAidlInterface = IMyAidlInterface.Stub.asInterface(iBinder);
handler.post(new Runnable() {
@Override
public void run() {
//注冊回調(diào)
if (iMyAidlInterface != null){
try {
iMyAidlInterface.registerListener(serviceCallBack);
} catch (RemoteException e) {
e.printStackTrace();
}
}
}
});
}
@Override
public void onServiceDisconnected(ComponentName componentName) {
}
}
/**
* service回到client的類
*/
class ServiceCallBack extends IMyAidlCallBackInterface.Stub{
@Override
public void callback(final String tag, final String message) throws RemoteException {
runOnUiThread(new Runnable() {
@Override
public void run() {
text.append("tag="+tag+" message="+message);
}
});
}
}
}
看看效果吧,Client2(app2)發(fā)消息給Client1(app1)


順便說一句,提前打開Center服務(wù),因?yàn)閍ndroid 8.0之后的版本直接遠(yuǎn)程開啟其他App后臺進(jìn)程服務(wù),是行不通了,可以綁定一個前臺進(jìn)程,網(wǎng)上方法有很多,我這里就簡單處理了
源碼我都放在github:MessageCenter
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Android提高之SurfaceView的基本用法實(shí)例分析
這篇文章主要介紹了Android提高之SurfaceView的基本用法,非常實(shí)用的功能,需要的朋友可以參考下2014-08-08
Android編程實(shí)現(xiàn)向SD卡寫入數(shù)據(jù)的方法
這篇文章主要介紹了Android編程實(shí)現(xiàn)向SD卡寫入數(shù)據(jù)的方法,涉及Android針對SD卡狀態(tài)判斷,文件及權(quán)限操作等相關(guān)技巧,需要的朋友可以參考下2016-04-04
Android ApiDemo示例工程的創(chuàng)建
本文主要介紹Android ApiDemo示例工程的創(chuàng)建,這里SDK中的示例工程做了大致介紹,并說明如何創(chuàng)建ApiDemo 示例工程,有需要看自帶代碼的朋友可以參考下2016-09-09
Android實(shí)現(xiàn)定時任務(wù)及鬧鐘
這篇文章主要為大家詳細(xì)介紹了Android實(shí)現(xiàn)定時任務(wù)及鬧鐘,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下2020-06-06
Android跳轉(zhuǎn)到通訊錄獲取用戶名稱和手機(jī)號碼的實(shí)現(xiàn)思路
這篇文章主要介紹了Android跳轉(zhuǎn)到通訊錄獲取用戶名稱和手機(jī)號碼的實(shí)現(xiàn)思路,當(dāng)用戶點(diǎn)擊跳轉(zhuǎn)到通訊錄界面 并取通訊錄姓名和手機(jī)號碼 ,實(shí)現(xiàn)代碼簡單易懂,非常不錯感興趣的朋友一起看看吧2016-10-10
Android使用Dialog風(fēng)格彈出框的Activity
這篇文章主要為大家詳細(xì)介紹了Android使用Dialog風(fēng)格彈出框的Activity,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下2016-09-09

