有貨Android組件化下的路由實踐
隨著有貨App的業務不斷迭代,功能不斷累積,原有的項目架構逐漸出現了以下問題:業務模塊代碼邊界不清晰,耦合過重;業務代碼與通用代碼的耦合導致很多重複代碼;基礎組件庫的不完善導致了一些三方庫的重複。鑒於此,組件化勢在必行,一個簡易的架構分層圖如下:
單向依賴,業務組件相互之間無依賴關係,那業務組件之間的頁面跳轉該如何解決呢?
現在比較通用的一個解決辦法是採用路由,現在社區有很多開源路由框架,比如ARouter,DeepLinkDispatch,ActivityRouter,LiteRouter等,再結合有貨現有的業務跟組件化架構,基於以下幾點實現一個路由方案:
1. 註解配置,通過APT在編譯時去生成各個組件的路由表
2. AspectJ去匯總各個組件的路由表,同樣通過APT生成輔助代碼實現
3. 路由調用支持原本Bundle支持的各種數據類型,各種Activity跳轉的Flags,跳轉動畫以及支持startActivityForResult
4. 支持攔截器,特別是先跳轉登錄再跳轉請求的頁面這種非同步的場景,可以通過RxJava的Subject實現
5. Activity的參數自動注入,類似ButterKnife,這個優先順序不高
6. 路由後的結果回調
7. 兼容原本App中的老跳轉規則,可以將原來的流程對接到新的路由sdk
簡單用一個流程圖表示一下,下面會具體講:
對於上面說的幾點,我從路由使用的角度來詳細闡述一下。
1. 首先整個路由sdk有三部分組成
· router是一些代碼中用到的API
· router-annotation定義了一些需要用到的註解
· router-processor定義了註解處理器
2. 初始化
在Application的onCreate()里初始化路由sdk,所做的事情很簡單,只是初始化一個List,這個List負責匯總各個組件模塊中的路由。
3. 路由定義
· 這個註解會在編譯時由註解處理器來解析
· 此註解支持配置多個url
· url的格式:scheme://host/path/{paramKey},url正則匹配,為了不使url的解析過於複雜,這裡的param匹配只會解析成String類型,對於其餘的類型則可通過Router API手動添加
· url匹配舉例:yoho://detail/88
除了Router這個註解還需要一個RouterModule註解:
· 這個註解同樣在編譯時由註解處理器來解析,註解一個空類即可,它會生成一個類DetailModuleRouter,這個類生成在當前組件的包名下,用來匯總該組件下所有的Router註解並放入一個List中用於匹配
· 除此之外,註解處理器還需要在DetailModuleRouter中插入一段AspectJ調用代碼,用於匯總各個組件模塊路由:
簡單解釋一下,就是將該組件的路由module類加到一個匯總所有路由module類的List中,這個List就是上面第二步所說的初始化的List,加入的地方與時機便是由AspectJ來決定,這段AspectJ註解的意思就是切入路由sdk的初始化方法,在調用該方法後的代碼中去執行該組件的路由匯總工作,其他組件同理。這樣做主要是因為組件化後各個業務組件編寫代碼期間無依賴關係,只有編譯運行後才可見(參照得到的組件化方案),也就不能強引用各個組件的路由module類,而AspectJ則是在編譯期間AOP正好可以應對這個情況,由於項目中之前做其他功能已經引入了AspectJ,所以對於我們來說不是很重的選擇。
· 我們看下AspectJ後的位元組碼:
4. 編譯期所做的事情基本理完,下面就是正式調用Router相關的API,一個例子如下:
RouterCall代表了一次路由操作,用Builder模式去構造,有很多putXxx方法,可以去添加Bundle支持的各種數據類型,Activity相關的Flags(如Intent.FLAG_ACTIVITY_NEW_TASK),Activity直接跳轉的動畫等,這些數據都封裝在RouterMap這個類中,然後支持添加攔截器和routerCallback,這兒的攔截器是同步的,非同步的後面會說,route有一個重載的帶requestCode的方法,如果帶入一個大於0的值,則會去調用startActivityForResult。攔截器調用鏈參考了okHttp的實現,真正的路由跳轉操作也當成一個攔截器,放到所有攔截器的最後。下面是這個過程的一個簡單時序圖:
5. 非同步攔截器
· 並沒有放到路由sdk中,因為跟業務有一些耦合
· 我這裡用RxJava的PublishSubject來實現,Subject屬於Hot Observable,有點類似EventBus,但是可以當成一個專用的EventBus
· 一個簡單例子如下:
如果需要登錄則先路由到登錄,登錄成功後發射一下:sUserPublishSubject.onNext(sUser)則會跳轉到原先的路由頁面,要注意及時的dispose,否則界面會亂跳。
上面列出了路由實踐中重要的一些點,還有些未實現比如支持方法調用,安全考慮,會逐步完善。為方便開發,形成一份路由url映射的文檔很有必要,這個也可以在編譯時去生成,可以參考DeepLinkDispatch,不再贅述。
感謝社區優秀的路由庫和相關文章:
· https://www.jianshu.com/p/8a3eeeaf01e8
· https://github.com/airbnb/DeepLinkDispatch
· https://github.com/alibaba/ARouter
TAG:YOHO!(有貨) | 路由器 |