Android 組件化之通信(多模塊,多進程)

1. 引子

寫這篇文章主要是有兩個原因:

  1. 之前寫過一篇 Android組件化開發實踐 ,組件化最直接的表現形式就是工程中包含了多個業務Module,代碼要解耦,但是業務間要解耦幾乎是不可能的,于是就要涉及到業務間的通信,表現在代碼上就是Module間通信。其實在文章提到的ActivityRouter就是模塊間通信很好的一個library,但是其主要作為Activity Router來使用,傳遞數據的能力有限(當然稍微改造一下代碼,交換數據還是很容易解決的)。

  2. 最近看到了 Spiny 同學的 Android架構思考(模塊化、多進程) ,寫的非常好,在掘金上分享后得到了不少同學的點贊。尤其文中提到的多進程方案,自己也非常感興趣,于是就去看了源碼,很有想象力,但是在使用時個人感覺也有一些小問題,于是就fork了一份代碼,開始對代碼進行了一些修改,本文中將主要介紹一下這些修改。

2. 模塊間通信原理

我們先來看一下架構圖,圖片來源于 http://blog.spinytech.com/2016/12/28/android_modularization/

從A、B到N的多個Module都引用了Common庫,同時Main Module還引用了A、B、N這幾個Module,經過這樣的處理之后,所有的Module之間的相互調用就都消失了,耦合性降低,所有的通信統一都交給Router來處理分發,而注冊工作則交由Main Module去進行初始化。這個架構思想其實和Binder的思想很類似,采用C/S模式,模塊之間隔離,數據通過共享區域進行傳遞。模塊與模塊之間只暴露對外開放的Action,所以也具備面向接口編程思想。

架構圖中每個紅色的Action都是可以提供的服務,而Provider是一個服務的集合,每個Module中可以有一個或者多個Provider,當程序開始執行時,module會把Provider注冊到Router Module。Action服務請求流程如下:

  1. 任意代碼創建一個RouterRequest,包含Provider和Action信息,向Router進行請求。

  2. Router接到請求,通過RouterRequest的Provider信息,在內部的HashMap中查找對應的Provider。

  3. Provider接到請求,在內部的HashMap中查找到對應的Action信息。

  4. Action調用invoke方法。

  5. 返回invoke方法生成的ActionResult。

  6. 將Result封裝成RouterResponse,返回給調用者。

3. 多進程架構模塊通信原理

還是先來看下架構圖:

Router是JVM級別的單例模式,并不支持跨進程訪問。也就是說,你的后臺進程的所有Provider、Action,是注冊給后臺Router的。當你在前臺進程調用的時候,根本調用不到其他進程的Action。

解決方案是單獨提取一個Wide Router模塊,所有的Local Route與Wide Router通過進程間通信的方式建立連接,Action請求如果在Local Router中找不到時,則通過WideRouter與其它進程建立連接,WideRouter充當局域網之間的路由。一次跨進程的Action請求如下圖所示:

以上的內容主要來自于 Android架構思考(模塊化、多進程) ,目前也已經有了相應的demo,大家可以去嘗試一下,體驗多進程App的樂趣。

4. 可以改進的地方

關于ModularizationArchitecture的使用,有相應的文檔: ModularizationArchitecture 使用教程 。個人在使用后感覺又一些不太方便的地方,主要有三點:

4.1 通信數據格式問題

目前發起請求時傳遞的數據是 RouterRequest ,接收的數據是 RouterReponse ,兩種類型的數據中包含的只有字符串數據,在實際的進程間通信時傳遞的數據也是字符串(代碼中轉為了json數據)。這種方式不能傳遞自定義的數據,在數據使用時也要手動解析字符串,比較繁瑣。

其實Android為進程間通信提供了Parcelable,可以通過這種方式非常方便地傳遞數據。

4.2 線程切換問題

demo中采用新建線程的方式請求異步數據:

代碼看起來不夠優雅,采用Rxjava 的方式會使得線程切換更加優雅,Router模塊可以使用Rxjava的方式返回結果。

4.3 Provider、Action 注冊問題

代碼中Provider、Action需要手動注冊,如果增加一個Action,需要有多個地方進行變動,這里可以采用apt的方式來自動進行注冊。

5. 解決方案

針對以上的三個問題,對代碼進行來部分修改,如下:

5.1 進程間通信數據格式的修改

請求數據 RouterResquest 和返回數據 MaActionResult 分別實現了Parcelable接口,并且分別提供了兩個可以自定義的成員變量 requestObject 和 result ,用戶在建立請求數據 RouterResquest 和返回數據 MaActionResult 可以把自定義的數據傳遞進去,需要注意的是傳遞的自定義類型也要實現Parcelable接口。

5.2 Provider、Action自動生成

5.3 Rxjava 的引入

引入Rxjava之后,修改LocalRoute的route方法,使之返回 Observable<MaActionResult> ,在調用時可以非常方便地使用Rxjava切換線程:

6. 使用教程

項目地址: https://github.com/wutongke/ModularizationArchitecture

6.1 在項目中集成

6.1.1 在project的build.gradle中設置maven地址:

dependencies塊中支持apt:

6.1.2 所有Module中配置apt插件:

dependencies塊中設置:

6.2 創建自定義Application

6.2.1 實際Application

我們知道一個app中只有一個Application,所以在主Module中定義Application,然后在其它模塊中根據需要實現邏輯Application即可,然后啟動時注冊邏輯Application,即可管理其生命周期:

當然這個自定義的Application需要注冊到manifest文件中。

使用多進程提供服務的模塊需要繼承 LocalRouterConnectService ,并且在manifest中注冊服務:

6.2.2 邏輯Application

邏輯Application通過繼承BaseApplicationLogic,實現相應的方法即可被回調。

6.3 自定義Provider和Action

定義Provider

定義Action

可以看到定義Provider和Action時分別使用了 @Provider 和 @Action 注解,這樣可以在程序編譯時完成自動的注冊,不需要手動注冊到Router了。

其中 @Provider 需要設置進程名字, @Action 需要設置進程名字和注冊到的Provider名字:

6. 4 調用Action

6.4.1 建立Action調用

首先需求建立一個請求 RouterRequest ,說明要請求的內容:

可以通過RouterRequestUtil的obtain方法快速建立請求,上例中請求的Action位于”com.spinytech.maindemo:music”進程,Provider是”music”,Action是”play”,并且傳遞了相應的參數new Song(“see you”)。

然后使用Rxjava的方式請求Action:

6.4.2 處理請求

在music模塊中處理剛剛發出的請求,6.3中定義的Provider和Action其實就是處理6.4.1中的請求的,并且返回了 MaActionResult :

7. 總結

6小節介紹了 ModularizationArchitecture 的基本使用, ModularizationArchitecture 提供了完整的demo,大家可以clone代碼參考,有任何問題可以在該項目下提issue,歡迎交流。

 

 

來自:http://mp.weixin.qq.com/s?__biz=MzA3OTk4ODkwNA==&mid=2449245748&idx=1&sn=7413078e04770dff1bda56253fa24f31&chksm=8ba337f3bcd4bee5f40f494cd9c9228246097f10fc0a65a38b6e641878941f25981fca005169&scene=0#rd

 

 本文由用戶 Tor81I 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!