[Android]你不知道的Android進程化(4)--進程通信AIDL框架

大家好,我系蒼王。

以下是我這個系列的相關文章,有興趣可以參考一下,可以給個喜歡或者關注我的文章。

[Android]如何做一個崩潰率少于千分之三噶應用app--章節列表

Google爸爸,聽說要將一些插件化hook系統的變量屬性禁用,Android P之后很可能將會不再有插件化、熱更新、主題變換、資源加固等騷操作。試圖hook,你將會看到 NoSuchFieldException 或者 NoSuchMethodException 等錯誤提示。
可見文章Android P 調用隱藏API限制原理中對api隱藏說明
具體通過@hide的注釋讓屬性提示變量不存在。
這樣就會要求app上線前測試更加嚴謹,而不是在上線后通過各種修復替換功能等方式,每周發版的日子,將不會出現了,不停歇的加班。
RN技術其原理涉及到view的渲染,暫時并未受到波及。
現在國內,有繼續走RN的,各大廠有走類似小程序方向的快應用,都是使用js語法,寫web還能拯救一堆程序猿啊。

接下來說一下進程通信,其實任何的進程通信方式,都可以在組件化開發中使用。
Android中進程間通信的方式
1.Aidl
2.Messenger
3.Content provider
4.Socket
5.文件共享

前三個都是基于binder機制實現的。
本節想要介紹的是使用aidl做的進程通信,單單使用aidl進行通信其實并不難。原理也有很多文章介紹過,但是如何設計一個通用的aidl通信架構,就需要考究了。
這里介紹的是ModularizationArchitecture中使用的aidl的通信架構。


ModularizationArchitecture通信架構

這里ModularizationArchitecture架構使用了aidl作為路由傳輸的實現。

文件結構

1.每個需要通信的module,都需要繼承MaProvider類,然后在BaseApplicationLogic啟動的時候注冊。
2.MaAction作為觸發的事件,繼承出來改寫其方法,invoke方法是事件實現。需要在MaProvider中注冊事件。
3.MaActionResult是事件結果回調。
4.LocalRouter是當前進程調用MaAction中的invoke執行方法。
5.WideRouter是跨進程調用時使用,需要在MaApplication啟動的時候注冊將module中的的LocalRouterConnectService。

注冊提供內容



注冊進程路由信息到廣域路由中

public class MyApplication extends MaApplication {//注冊進程路由信息到廣域路由@Overridepublic void initializeAllProcessRouter() {WideRouter.registerLocalRouter("com.spinytech.maindemo",MainRouterConnectService.class);WideRouter.registerLocalRouter("com.spinytech.maindemo:music",MusicRouterConnectService.class);WideRouter.registerLocalRouter("com.spinytech.maindemo:pic",PicRouterConnectService.class);}//初始化進程啟動@Overrideprotected void initializeLogic() {registerApplicationLogic("com.spinytech.maindemo",999, MainApplicationLogic.class);registerApplicationLogic("com.spinytech.maindemo",998, WebApplicationLogic.class);registerApplicationLogic("com.spinytech.maindemo:music",999, MusicApplicationLogic.class);registerApplicationLogic("com.spinytech.maindemo:pic",999, PicApplicationLogic.class);}//是否使用多進程@Overridepublic boolean needMultipleProcess() {return true;}
}
復制代碼

進程初始化的時候注冊MaProvider到進程路由中

public class MainApplicationLogic extends BaseApplicationLogic {@Overridepublic void onCreate() {super.onCreate();//注冊ProviderLocalRouter.getInstance(mApplication).registerProvider("main",new MainProvider());}
}
復制代碼

為每個Provider綁定可以觸發的Action任務

public class MainProvider extends MaProvider {@Overrideprotected void registerActions() {registerAction("sync",new SyncAction());registerAction("async",new AsyncAction());registerAction("attachment",new AttachObjectAction());}
}
復制代碼

下面是進程內同步通信


進程內同步通信

進程內調用

RouterResponse response = LocalRouter.getInstance(MaApplication.getMaApplication())  //進程中單例LocalRouter.route(MainActivity.this, RouterRequest.obtain(MainActivity.this) //在緩存池中獲取請求.provider("main")   //設定provider.action("sync")     //設定調用的action.data("1", "Hello")   //設定數據.data("2", "World"));
復制代碼

通過注冊的內容找到相應的action,然后調用action中的invoke方法

public RouterResponse route(Context context, @NonNull RouterRequest routerRequest) throws Exception {Logger.d(TAG, "Process:" + mProcessName + "\nLocal route start: " + System.currentTimeMillis());RouterResponse routerResponse = new RouterResponse();// Local request//檢查domain是不是在同一個進程if (mProcessName.equals(routerRequest.getDomain())) {HashMap<String, String> params = new HashMap<>();Object attachment = routerRequest.getAndClearObject();params.putAll(routerRequest.getData());Logger.d(TAG, "Process:" + mProcessName + "\nLocal find action start: " + System.currentTimeMillis());//通過provider索引到actionMaAction targetAction = findRequestAction(routerRequest);routerRequest.isIdle.set(true);Logger.d(TAG, "Process:" + mProcessName + "\nLocal find action end: " + System.currentTimeMillis());routerResponse.mIsAsync = attachment == null ? targetAction.isAsync(context, params) : targetAction.isAsync(context, params, attachment);// Sync result, return the result immediately// 同步調用.if (!routerResponse.mIsAsync) {//調用action的實現MaActionResult result = attachment == null ? targetAction.invoke(context, params) : targetAction.invoke(context, params, attachment);//包裝responserouterResponse.mResultString = result.toString();routerResponse.mObject = result.getObject();Logger.d(TAG, "Process:" + mProcessName + "\nLocal sync end: " + System.currentTimeMillis());}
復制代碼

下面是進程內異步通信


進程內異步通信[圖片上傳中...(屏幕快照 2018-03-30 下午12.36.03.png-c9d7e7-1522384627443-0)]

route方法中在mIsAsync設定是否異步

public RouterResponse route(Context context, @NonNull RouterRequest routerRequest) throws Exception {Logger.d(TAG, "Process:" + mProcessName + "\nLocal route start: " + System.currentTimeMillis());RouterResponse routerResponse = new RouterResponse();// Local request//檢查domain是不是在同一個進程if (mProcessName.equals(routerRequest.getDomain())) {...// Sync result, return the result immediately// 同步調用.if (!routerResponse.mIsAsync) {...}// Async result, use the thread pool to execute the task.//異步調用else {//創建異步任務LocalTask task = new LocalTask(routerResponse, params,attachment, context, targetAction);//通過線程池調用routerResponse.mAsyncResponse = getThreadPool().submit(task);}
復制代碼

異步調用任務是使用Callback任務

    //使用Future Callable的方式使用線程池private class LocalTask implements Callable<String> {private RouterResponse mResponse;private HashMap<String, String> mRequestData;private Context mContext;private MaAction mAction;private Object mObject;public LocalTask(RouterResponse routerResponse, HashMap<String, String> requestData,Object object, Context context, MaAction maAction) {this.mContext = context;this.mResponse = routerResponse;this.mRequestData = requestData;this.mAction = maAction;this.mObject = object;}@Overridepublic String call() throws Exception {//調用action中的invoke方法MaActionResult result = mObject == null ? mAction.invoke(mContext, mRequestData) : mAction.invoke(mContext, mRequestData, mObject);mResponse.mObject = result.getObject();Logger.d(TAG, "Process:" + mProcessName + "\nLocal async end: " + System.currentTimeMillis());return result.toString();}}
復制代碼

下面是跨進程通信


跨進程通信

使用aidl調用廣域的WideRouter

//檢查domain是不是在同一個進程if (mProcessName.equals(routerRequest.getDomain())) {...}// IPC requestelse {//獲取進程domainString domain = routerRequest.getDomain();String routerRequestString = routerRequest.toString();routerRequest.isIdle.set(true);//檢查是不已經綁定了廣域路由WideRouterif (checkWideRouterConnection()) {Logger.d(TAG, "Process:" + mProcessName + "\nWide async check start: " + System.currentTimeMillis());//If you don't need wide async check, use "routerResponse.mIsAsync = false;" replace the next line to improve performance.//檢查是同步還是異步routerResponse.mIsAsync = mWideRouterAIDL.checkResponseAsync(domain, routerRequestString);Logger.d(TAG, "Process:" + mProcessName + "\nWide async check end: " + System.currentTimeMillis());}// Has not connected with the wide router.else {//調用連接廣域路由WideRouterrouterResponse.mIsAsync = true;ConnectWideTask task = new ConnectWideTask(routerResponse, domain, routerRequestString);routerResponse.mAsyncResponse = getThreadPool().submit(task);return routerResponse;}//同步調用if (!routerResponse.mIsAsync) {//aidl傳輸給相關進程的LocalRouterConnectServicerouterResponse.mResultString = mWideRouterAIDL.route(domain, routerRequestString);Logger.d(TAG, "Process:" + mProcessName + "\nWide sync end: " + System.currentTimeMillis());}// Async result, use the thread pool to execute the task.//異步調用else {//設定廣域調用任務WideTask task = new WideTask(domain, routerRequestString);routerResponse.mAsyncResponse = getThreadPool().submit(task);}}//返回ReouterResponsereturn routerResponse;
復制代碼

廣域路由連接檢測,調用aidl連接到WideRouterConnectService

    private class ConnectWideTask implements Callable<String> {private RouterResponse mResponse;private String mDomain;private String mRequestString;public ConnectWideTask(RouterResponse routerResponse, String domain, String requestString) {this.mResponse = routerResponse;this.mDomain = domain;this.mRequestString = requestString;}@Overridepublic String call() throws Exception {Logger.d(TAG, "Process:" + mProcessName + "\nBind wide router start: " + System.currentTimeMillis());//綁定WideRouterConnectServiceconnectWideRouter();int time = 0;while (true) {//等待廣域路由綁定完成if (null == mWideRouterAIDL) {try {Thread.sleep(50);} catch (InterruptedException e) {e.printStackTrace();}time++;} else {break;}//超過30秒就放棄,拋出錯誤if (time >= 600) {ErrorAction defaultNotFoundAction = new ErrorAction(true, MaActionResult.CODE_CANNOT_BIND_WIDE, "Bind wide router time out. Can not bind wide router.");MaActionResult result = defaultNotFoundAction.invoke(mApplication, new HashMap<String, String>());mResponse.mResultString = result.toString();return result.toString();}}Logger.d(TAG, "Process:" + mProcessName + "\nBind wide router end: " + System.currentTimeMillis());//調用關于路由傳輸到對應的進程路由String result = mWideRouterAIDL.route(mDomain, mRequestString);Logger.d(TAG, "Process:" + mProcessName + "\nWide async end: " + System.currentTimeMillis());return result;}}
復制代碼

WideRouterConnectService對對應的進程路由分發通信,監聽返回。

//廣域路由處理IWideRouterAIDL.Stub stub = new IWideRouterAIDL.Stub() {@Overridepublic boolean checkResponseAsync(String domain, String routerRequest) throws RemoteException {//檢查是否異步調動return WideRouter.getInstance(MaApplication.getMaApplication()).answerLocalAsync(domain, routerRequest);}@Overridepublic String route(String domain, String routerRequest) {try {//廣域路由分發到對應的進程路由中return WideRouter.getInstance(MaApplication.getMaApplication()).route(domain, routerRequest).mResultString;} catch (Exception e) {e.printStackTrace();return new MaActionResult.Builder().code(MaActionResult.CODE_ERROR).msg(e.getMessage()).build().toString();}}@Overridepublic boolean stopRouter(String domain) throws RemoteException {//停止連接進程路由return WideRouter.getInstance(MaApplication.getMaApplication()).disconnectLocalRouter(domain);}};
復制代碼

根據domain分發到對應進程的ILocalRouterAIDL

public RouterResponse route(String domain, String routerRequest) {Logger.d(TAG, "Process:" + PROCESS_NAME + "\nWide route start: " + System.currentTimeMillis());RouterResponse routerResponse = new RouterResponse();//是否已經被要求停止任務if (mIsStopping) {MaActionResult result = new MaActionResult.Builder().code(MaActionResult.CODE_WIDE_STOPPING).msg("Wide router is stopping.").build();routerResponse.mIsAsync = true;routerResponse.mResultString = result.toString();return routerResponse;}//廣域路由不能作為調用對象if (PROCESS_NAME.equals(domain)) {MaActionResult result = new MaActionResult.Builder().code(MaActionResult.CODE_TARGET_IS_WIDE).msg("Domain can not be " + PROCESS_NAME + ".").build();routerResponse.mIsAsync = true;routerResponse.mResultString = result.toString();return routerResponse;}//獲取對應進程路由的對象ILocalRouterAIDL target = mLocalRouterAIDLMap.get(domain);if (null == target) {//是否已經綁定了本地路由,沒有就啟動綁定if (!connectLocalRouter(domain)) {MaActionResult result = new MaActionResult.Builder().code(MaActionResult.CODE_ROUTER_NOT_REGISTER).msg("The " + domain + " has not registered.").build();routerResponse.mIsAsync = false;routerResponse.mResultString = result.toString();Logger.d(TAG, "Process:" + PROCESS_NAME + "\nLocal not register end: " + System.currentTimeMillis());return routerResponse;} else {// Wait to bind the target process connect service, timeout is 30s.Logger.d(TAG, "Process:" + PROCESS_NAME + "\nBind local router start: " + System.currentTimeMillis());int time = 0;//等待完成綁定進程連接while (true) {target = mLocalRouterAIDLMap.get(domain);if (null == target) {try {Thread.sleep(50);} catch (InterruptedException e) {e.printStackTrace();}time++;} else {Logger.d(TAG, "Process:" + PROCESS_NAME + "\nBind local router end: " + System.currentTimeMillis());break;}//設定30s超時if (time >= 600) {MaActionResult result = new MaActionResult.Builder().code(MaActionResult.CODE_CANNOT_BIND_LOCAL).msg("Can not bind " + domain + ", time out.").build();routerResponse.mResultString = result.toString();return routerResponse;}}}}try {Logger.d(TAG, "Process:" + PROCESS_NAME + "\nWide target start: " + System.currentTimeMillis());//對應進程調用返回String resultString = target.route(routerRequest);routerResponse.mResultString = resultString;Logger.d(TAG, "Process:" + PROCESS_NAME + "\nWide route end: " + System.currentTimeMillis());} catch (RemoteException e) {e.printStackTrace();MaActionResult result = new MaActionResult.Builder().code(MaActionResult.CODE_REMOTE_EXCEPTION).msg(e.getMessage()).build();routerResponse.mResultString = result.toString();return routerResponse;}return routerResponse;}
復制代碼

基本原理就介紹到這里了。
1.aidl是google為Android進程通信提供的方式,使用了代理模式,其內部集成了IBinder,使用了Binder的方式通信,已經成為套路的規則,維護成本低。
2.當序列化后的數據單元過大時,就會出問題,報出android.os.TransactionTooLargeException。其數據量限制為1M
3.原理上說就是binder只拷貝一次,使用虛擬內存和物理內存頁映射,比socket高效,也安全。
4.這里介紹的框架,其中是通過本地路由和廣域路由間的傳送和切換來完成。只能交流變量和調用方法,無法通過aidl獲取資源。本地路由能力并未有ARouter使用的方便,進程內對無法提供獲取Fragment View等資源獲取,可以考慮拓展。但是此本地和廣域路由設計非常優秀。
5.wutongke有出了一個框架加上編譯時注解的優化版github.com/wutongke/Mo…

下一節將會繼續介紹Messenger進程通信框架,敬請期待。


Android進程化學習


本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/255071.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/255071.shtml
英文地址,請注明出處:http://en.pswp.cn/news/255071.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

在未啟動程序情況 點擊視圖設計器 彈出未將對象引用窗體的解決方案

請問下 在未運行程序情況 點擊視圖設計器 彈出未將對象引用窗體 解決方案&#xff1a;1.看后臺進程是不是相關的進程在啟動&#xff0c;如果有關閉進程&#xff1b;重啟vs,即可2.重啟電腦轉載于:https://www.cnblogs.com/yang12311/p/5593838.html

圖像配準的步驟

目前&#xff0c;很難找到一種普適的方法能夠應對所有的配準情況&#xff0c;任何一種配準算法都必須考慮圖像的成像原理、幾何變形、噪聲影響、配準精度等因素。不過&#xff0c;從原理上將&#xff0c;配準算法可以大致分為以下四個步驟&#xff1a; &#xff08;1&#xff0…

Jm86中的encode_one_macroblock注釋

Jm86中的encode_one_macroblock注釋 /*! ************************************************************************************** /brief* Mode Decision for a macroblock* //該函數的作用是編碼一個宏塊&#xff08;包括幀間、幀內、幀內預測的方式&#xff09;。*…

Python之路【第十七篇】:裝飾器

寫代碼的時候有一個原則&#xff0c;開放封閉原則(面向對象)&#xff1a;對某些東西開放&#xff0c;對某些封閉&#xff0c;在裝飾器這里&#xff0c;函數內部是封閉的&#xff0c;不允許改變函數的內部。 裝飾器用來裝飾函數&#xff0c;可以讓函數在執行之前或者執行之后&am…

HALCON示例程序measure_chip.hdev芯片封裝檢測

HALCON示例程序measure_chip.hdev芯片封裝檢測 示例程序源碼&#xff08;加注釋&#xff09; 關于顯示類函數解釋 dev_update_off () read_image (Image, ‘die_on_chip’) get_image_size (Image, Width, Height) dev_close_window () dev_open_window (0, 0, Width * 2, He…

工業機器人智能發展:視覺和觸覺感應簡化

機器人工業協會&#xff08;Robotic Industries Association&#xff09;指出&#xff0c;從2003到2005年間&#xff0c;北美機器人工業以20%的平均年增長率發展。在汽車市場需求疲軟以及外國廠商的壓力不斷增加的背景下&#xff0c;這一成就是如何取得的&#xff1f;成本的普遍…

ASP站點無法訪問怎么辦

確保啟用了目錄瀏覽功能 轉載于:https://www.cnblogs.com/acetaohai123/p/6571257.html

五、案例-指令參考-freemarker指令、表達式

案例-指令參考描述&#xff1a;本人自己測試寫了一遍&#xff0c;如有錯的地方&#xff0c;懂freemarker的朋友望指點指點&#xff01; 案例-指令參考 表達式 一、 Assign 1、<#assign name1"北京" name2"上海" name3"廣東"> 調用&#xf…

PartitionMotionSearch()函數

encode_one_macroblock()函數中的運動估計分為兩大塊&#xff0c;對于宏塊級的三種模式&#xff0c;分塊后直接對patition依次調用PartitionMotionSearch()函數&#xff1b;而對于亞宏塊級的&#xff08;含8x8, 8x4,4x8,4x4&#xff09;模式&#xff0c;首先將宏塊拆分為4個88子…

201521123017 《Java程序設計》第4周學習總結

1. 本周學習總結 2. 書面作業 Q1.注釋的應用 使用類的注釋與方法的注釋為前面編寫的類與方法進行注釋&#xff0c;并在Eclipse中查看。(截圖) Q2.面向對象設計(大作業1&#xff0c;非常重要) 2.1 將在網上商城購物或者在班級博客進行學習這一過程&#xff0c;描述成一個故事。…

完整的VAL3程序

start() begin//延時10秒 delay(5)//初始化變量call init()//清空原有運動堆棧resetMotion()//建立上電任務taskCreate "robotpower",100,robotpower()wait(isPowered())//建立生產任務taskCreate "ProductionCycle",10,ProductionCycle()//建立安全區域…

iOS WebView 加載本地資源(圖片,文件等)

NSString *path [[NSBundle mainBundle] pathForResource:"關于.docx" ofType:nil]; NSURL *url [NSURL fileURLWithPath:path]; NSLog("%", [self mimeType:url]); //webview加載本地文件&#xff0c;可以使用加載數據的方式 //第一個誒參數是一個N…

本文以H264視頻流為例,講解解碼流數據的步驟。

本文以H264視頻流為例&#xff0c;講解解碼流數據的步驟。 為突出重點&#xff0c;本文只專注于討論解碼視頻流數據&#xff0c;不涉及其它&#xff08;如開發環境的配置等&#xff09;。如果您需要這方面的信息&#xff0c;請和我聯系。 準備變量 定義AVCodecContext。如…

2008-2021年商業銀行數據(農商行、城商行、國有行、股份制銀行)

2008-2021年商業銀行數據&#xff08;農商行、城商行、國有行、股份制銀行&#xff09; 1、時間&#xff1a;2008-2021年 2、范圍&#xff1a;1700銀行 3 、指標&#xff1a;證券簡稱、year、證券代碼、資產總計、負債合計、所有者權益合計、利潤總額、凈利潤、貸款總額、存…

EPSON 任務同步 改寫

有時需要在多個任務執行之前來使它們同步。如果預先知道執行每項任務所需要的時間&#xff0c;它們就可以通過簡單地等待由最慢的任務產生的信號來實現同步。然而&#xff0c;如果不知道那個任務是最慢的&#xff0c;就需要使用一個更復雜的同步化機制&#xff0c;如下所示VAL …

線程池的簡單使用

創建指定線程數量的線程池 private static ExecutorService scheduledTaskFactoryExecutor null;private boolean isCancled false;private static class ThreadFactoryTest implements ThreadFactory { Overridepublic Thread newThread(Runnable r) { Thread threa…

異常--自定義異常類

為什么要調用父類構造器? http://blog.csdn.net/rockpk008/article/details/52951856 轉載于:https://www.cnblogs.com/dwj-ngu/p/6576382.html

利用ffmpeg來進行視頻解碼的完整示例代碼

&#xff08;轉&#xff09;利用ffmpeg來進行視頻解碼的完整示例代碼&#xff08;H.264&#xff09; Decode() { FILE * inpf; int nWrite; int i,p; int nalLen; unsigned char * Buf; int got_picture, consumed_bytes; unsigned char *DisplayBuf; Displ…

安卓觀看免費視頻

http://www.imooc.com/search/course?wordsAndroid%E6%94%BB%E5%9F%8E%E7%8B%AE%E7%AC%AC%E4%B8%80%E8%AF%BE&page3 http://www.imooc.com/course/list?candroid&src360onebox http://www.bilibili.com/video/av2788563/index_4.html http://www.imooc.com/course/pr…

EtherCAT 網站鏈接

http://www.ethercat.org.cn/cn.htm EtherCAT技術介紹 EtherCAT系統組成和工作原理 EtherCAT采用主從式結構&#xff0c;主站PC機采用標準的100Base-TX以太網卡&#xff0c;從站采用專用芯片。系統控制周期由主站發起&#xff0c;主站發出下行電報&#xff0c;電報的最大有效數…