當前位置:
首頁 > 最新 > 一個Android路由框架的誕生之路

一個Android路由框架的誕生之路

經過前面三篇文章,相信大家對組件化都有了一定程度的理解。

在這個過程中一直強調了組件化的一個基礎設施:路由!沒有它組件化可以說是寸步難行,本篇文章我們就來談談一個組件化路由框架誕生過程中的那些思考

1、為什麼需要路由

這個問題其實我們之前談到過,而且有過組件化實踐或者嘗試的同學一定有切身感受。明確一個前提:各個業務模塊之間不會是相互隔離而是必然存在一些交互的;

在Module A需要跳轉到Module B某界面,而我們一般都是使用強引用的Class顯式的調用;

在Module A需要調用Module B提供的方法,例如別的Module調用用戶模塊退出登錄的方法;

這兩種調用形式大家很容易明白,正常開發中大家也是毫不猶豫的調用。但是我們在組件化開發的時候卻有很大的問題:

模塊B的Activity Class在自己的Module B,那Module A必然引用不到,顯式跳轉行不通;

同理,直接去調用某個Module的方法也行不通;

由此:必然需要一種支持組件化需求的交互方式,提供UI跳轉以及方法調用的能力。

2、一個路由庫需要滿足什麼

首先這個路由庫也是一個技術組件,在整體組件化層次的設計中處於Lib層,作為一項基礎庫。那麼路由庫不僅僅需要滿足自身的能力,同時勢必要滿足一項基礎庫該有的條件:

Api友好,接入簡單、低成本

具備UI跳轉和方法調用的能力

功能穩定

可定製化

3、淘汰過的方式

任何系統或框架,雖然在高版本中看起來都很完美,但是實際上一開始並非就是如此,都是一步步實踐、迭代改善到基於當前相對完美狀態的。比如我們之前就思考過如下方式:

3.1、基於隱式意圖

各位老司機都知道,Android中打開一個Activity,可以有兩種方式,顯示意圖和隱式意圖。既然顯式意圖導致了強引用,那麼我們使用隱式意圖,既可以打開Activity,同時也不會造成Module間的強引用。

評價:這種方式確實可以完成路由的UI跳轉功能,但是依賴於Manifest文件的修改,同時參數也存在不便傳遞的問題,因此不做推薦。

3.2、基於事件,使用廣播或EventBus

這種思路也很容易想到,既然不能直接交互,那麼就隱式的來,在需要交互的地方發通知,然後接收方根據不同的通知類型做出不同的處理。

評價:這種交互的方式是可行的,但是可以明顯看出,比較複雜,對於界面跳轉比較多的場景,接入及維護成本較高。

3.3、調用一個固定的方法

我們在需要交互的類中加上方法,方法簽名固定,然後給交互類打上一個標籤。這樣在別的組件中我們需要這個交互類的時候通過標籤拿到,調用這個固定的方法。思路是這樣,以下提供一種方式的偽代碼,有不同的實現。

備註使用HashMap作為參數的原因:每個交互類需要的參數不一樣,而方法簽名必須固定才能通過介面去調用,傳遞HashMap這個參數可以包含多個不同類型的參數。

評價:最不推薦,使用繁瑣,侵入性太強,改造成本極大。

4、一種好的路由實踐

總結以上幾種不好的實踐方式,都在於侵入性強,接入及維護成本高等。那反過來推就是一個好的路由需要具備低侵入性、易接入、自動化等特性

上述第三種方案我們可以吸收一點的是每個交互類打上一個標籤,記錄這個映射關係,方便在別的Module進行獲取。

順著這個映射往下想,這個映射保存了標籤和Activity,那麼打開Activity只需要知道這個標籤即可。舉例:標籤A和ActivityA對應,那麼我們只要遇到標籤A就知道它想要打開的是ActivityA。同時如果我們處理好了打開Activity需要的傳參問題就離自動化邁出了一大步。

問題就簡化成了兩個:

映射關係,我們可以使用String字元串作為標籤,既保證通用性又可以保證唯一性。利用一個Map保存這個字元串和Activity的映射關係,這樣可以保證在別的Module能通過字元串獲取到我們需要的Activity

傳參以及Activity各種特性(利用動畫、onActivityResult生命周期)的支持

關於第二個問題實際上就是將這個字元串儘可能多的解析到Android多需要的數據,比如參數傳遞、動畫、生命周期等。關於這個解析可以有兩種方式:

直接簡單粗暴在String後面拼一個參數,這個參數的格式是Json,到達目標界面之後目標界面再去解析;

制定一定規則通過路由就解決好,到目標界面直接像正常Android開發一樣去獲取;

5、方法調用的實現

方法調用看起來都可以通過上述:基於事件及調用一個固定的方法等方式來實現,但是使用起來必定複雜無比,各個Module之間交互不僅改造困難,維護成本也很高。

注意各個Module向外提供的方法必定不一樣:需要不同的方法簽名。而且從改造及維護成本考慮,最好可以像是在一個Module里一樣直接調用,IDE可以自動提示出來方法參數。

那我們就想把Module向外提供的方法內聚到一個類里,只向外暴露這個類,簡稱這個Module的交互服務類。這樣別的Module調用的時候就可以想直接調用普通類的方法一樣簡單方便了。

那我們就剩下一個問題:別的Module如何獲取你的交互服務類呢?很容易想到上面提到的映射,但是此種場景下如果使用字元串做Key真的可以嗎? 如果使用字元串做Key,別的Module拿到的Value只能確定是一個Class,具體的Class類型卻不清楚,調用具體的方法尤其是被IDE提示,更是不可能。問題又簡化成了如何讓我們知道拿到的Class中有哪些方法呢?

經過多次思考,終於想到了一個解決方案:Module需要向外暴露的方法,我們通過一個Interface來定義,這個Interface定義在Lib層也就是說每個Module都可以訪問到,而保存映射關係的Key我們也使用這個Interface。那麼映射表裡保存的就是:

那麼別的Module在獲取這個服務類時就可以直接通過在Lib層定義的Interface來獲取,然後通過泛型轉換成這個介面,而後直接調用相應方法即可,就像調用一個普通方法一樣簡單

6、路由的最佳實踐

6.1、編譯時註解

經過四、五兩節我們知道了路由相對較好的實踐,但同時我們能否讓這個過程自動化呢?其實可以藉助編譯時註解技術自動生成映射表,這樣在接入的時候就更加簡單方便,只需要在對應的Activity上打上一個註解,配置相應的字元串,這個映射表就自動生成。

6.2、攔截器


在實際開發中,我們經常會遇到些統一的操作,比如某些應用是需要用戶先登陸的,那麼在用戶瀏覽之後的下一步操作時用戶進行各種點擊都需要進行判斷是否登陸,未登錄則跳轉到登陸界面,登陸之後則放行。

正常情況我們需要在每一個點擊的地方進行判斷,但是明顯費時費力,既然我們已經做了路由,所有的界面跳轉都需要經過我們,那我們自然可以進行統一的判斷,在路由進行分發時候進行判斷,滿足攔截器條件則進行攔截。

6.2.2、重定向

如果我們需要對App的功能進行A/BTest,我們該如何進行呢?方式肯定有很多,但是不一定通用。注意我們已經有了路由,結合路由來做A/BTest的話更加方便:

首先我們給路由加一個攔截器,每一條跳轉都會經過這個攔截器的判斷;

通過路由實現界面跳轉,在路由解析過程中我們識別到了需要跳轉的是A模塊;

經過攔截器的判斷,如果A/BTest實驗命中的是B模塊,則將這個路由進行重定向到B模塊;

備註:重定向的好處還有更多,比如緊急情況下的熱修復替換成H5界面等。

6.3、過程監聽

就是監聽打開Activity的過程,如

打開前進行數據的準備;

打開後的回調;

未匹配到目標Activity的降級等;

本文主要介紹一個Android路由框架誕生過程中的思考,在下篇文章將會具體推薦一個路由框架。

喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 雙十二技術哥 的精彩文章:

TAG:雙十二技術哥 |