BlockFramework —— 客戶端模塊化業務開發框架
前言
在大型 APP 的開發進程中,多個業務方向或團隊共同開發同一頁面的現象屢見不鮮。倘若沒有良好的架構作為支撐,各業務之間的邏輯極易相互耦合,進而致使架構迅速惡化,這無疑會使業務開發與維護的成本增加。BlockFramework 作為一套客戶端業務解耦框架,具備業務分層、組裝以及協同的能力,業務方基于此框架能夠輕易實現業務解耦,獨立開展邏輯迭代,從而提升架構的穩定性,降低維護成本,并提高業務迭代的效率。BlockFramework 主要有 4 大特性:
- 「清晰的業務解耦機制」:開發者使用 BlockFramework 能夠輕松地將復雜的業務邏輯拆解成多個獨立的子「Block」,實現代碼上的物理隔離,不同業務的開發者只需要聚焦于所屬業務Block開發,降低代碼復雜度從而提升人效;同時Block支持跨場景復用,開發者可將基礎能力抽離成獨立的Block后應用到不同的場景中,減少冗余代碼,降低維護成本;
- 「高性能的UI組裝能力」:BlockFramework基于樹狀結構搭建界面UI,完美契合Android系統的布局樹結構,開發者只需要創建各個簡單的子布局Block,然后按照業務邏輯構建Block之間的父子關系,便能輕松搭建出一個復雜頁面。同時相較于常用的UI組裝方式,BlockFramework在UI組裝過程中集成了異步inflate、異步View創建等性能優化手段,高效優化頁面性能;
- 「豐富的通信機制」:BlockFramework提供了Block之間的多種通信機制(一對一、一對多、多對一),用于實現Block之間的聯動交互能力,通信機制通過接口抽象、事件訂閱/分發的方式,避免了Block與Block之間直接交互,保證了Block的獨立性和復用性;
- 「統一的開發范式」:BlockFramework 的接入和開發流程均提供了標準規范,使得不同業務的開發者能夠建立統一的開發認知,從而降低跨線研發成本,提升整體研發效率。
各種客制化場景,標紅區域為各Block:
BlockFramework已經在Github開源,歡迎大家多多支持。開源地址:https://github.com/bytedance/BlockFramework
Block單元
Block是BlockFramework的基本構成單元,一個復雜頁面可由多個Block組裝而成。Block支持UI配置,與安卓View樹結構完美適配,能夠渲染各種不同的場景;同時Block擁有獨立的,各Block可以單獨通過網絡獲取數據、渲染視圖等等。
樹狀管理機制
Block按照樹形結構進行組裝和管理,一個場景對應一顆Block樹,樹形結構的好處在于:
- 對于客戶端,通常基于頁面的布局結構進行業務開發,而布局結構對應于View樹結構,因此,Block構建樹狀結構更符合認知,通過Block樹便能清晰的看出整個頁面的邏輯結構;
- 樹是一種去中心化的結構,每個子Block只能被自己的父Block管理,Manager只需要驅動rootBlock便能操作整顆Block樹,能夠有效降低Manager自身的復雜度。
- 樹狀結構易于管理和分析,能夠通過防止樹形結構劣化調整頁面的結構劃分,理想狀態下,一個場景拆分的Block樹能夠達到一顆平衡樹結構。
Block提供了方式進行組裝,業務方能直觀的看出各Block之間的父子關系:
override fun assembleSubBlocks(assembler: BlockAssembler) {
assembler.assemble {
addBlock {
instance = {
MainContentBlock(blockContext)
}
parentId = R.id.main_content_block_container
}
addBlock {
instance = {
BottomInfoBlock(blockContext)
}
parentId = R.id.bottom_info_block_container
}
addBlock {
instance = {
RightInteractBlock(blockContext)
}
parentId = R.id.right_interact_block_container
}
}
}
生命周期管理
Block本身是一個生命周期單元,遵循Jetpack LifeCycle組件的生命周期節點設計,即onCreate() -> onDestory(),開發者能夠快速上手,同時易于對老場景進行遷移。
open class BaseBlock<DATA, MODEL : IBlockModel<DATA>>(val blockContext: IBlockContext) : AbstractLifecycleBlock() {
open fun onRegister() {}
override fun onCreate() {}
override fun onStart() {}
override fun onResume() {}
override fun onPause() {}
override fun onStop() {}
override fun onDestroy() {}
override fun onUnRegister() {}
}
「Block UML設計圖」
通信機制
在業務場景中,不同的業務模塊經常需要通信,如處于不同模塊的視圖需要根據用戶操作發生一些聯動。在這些情況下,如果讓模塊與模塊直接進行依賴,就無法避免模塊之間的耦合,這樣既無法保證模塊的獨立性,也影響可復用性。因此,Block框架基于SPI協議和觀察者模式實現了一套通信機制,各Block通過發現服務和廣播通信,能夠有效降低Block之間的耦合。
Block組內通信
Block通過一套MessageCenter機制實現內部通信,主要包括兩種形式:
- 「一對一調用」:基于SPI模式,對外暴露接口,其他Block可以通過接口獲取其他Block對外暴露的能力;
- 「一對多通信」:基于觀察者模式,可以通過定義Event進行事件廣播,所有訂閱該事件的Block默認都會收到該Event;
「Block通信范式樹形結構約束」
- 根據Block的樹形結構,對通信機制加入樹形結構的約束,即子節點只能訪問其父節點的service,如果訪問不到,再向上一級父Block查詢,直到找到為止,該方式能夠直觀的分析出一個場景拆分Block后的各Block之間的通信依賴情況。
Block組間通信
- 用于實現Block組件內部與外部邏輯交互,通過BlockDepend實現,業務場景向Block注入Depend后,在Block內部便能隨時獲取到Depend進行通信。
高性能特性
Block內置了不少高性能特性,相較Android原生的頁面構建機制,BlockFramework提供了異步組裝View異步數據綁定等多個優化手段,旨在更為極致的渲染頁面。
異步組裝View
Block支持將復雜頁面拆分一個個小單元,每一個小單元可對應一處簡單UI結構,如果不做優化,這個Block在inflate和組裝View時會默認在主線程執行,而實際上,由于每一個Block的View都是獨立進行inflate,因此,可以各Block的View創建的過程切換到子程序異步進行,完成后切換回到主線程組裝View,相較于整體在主線程創建View耗時更短,經過對比分析,異步組裝View能縮短約20%的耗時。
異步數據綁定
Block提供了異步數據綁定邏輯,支持開發者將耗時邏輯放到子線程執行,并提供了切換回主線程的回調,讓開發者更方便的執行耗時邏輯。
override fun bindModel(model: MODEL?) {
if (enableAsyncBind()) {
syncBind(model)
Executor.work().post {
asyncBind(model) {
Executor.main().post {
it.invoke()
}
}
}
} else {
syncBind(model)
asyncBind(model) {
it.invoke()
}
}
}
結語
BlockFramework是西瓜視頻團隊從業務中沉淀出的組件,經過不斷地完善和迭代,目前已經成為西瓜視頻詳情頁、橫屏內流、Feed列表、Feed卡片、業務播放器等多個核心場景的底層架構基礎,經過驗證,BlockFramework在性能和效率上都取得不錯的收益。后續我們會在更多的業務場景落地,同時在性能和架構上進一步優化。此外,BlockFramework已經推廣到字節系多個產品,尤其在西瓜鴻蒙版、鮮時光、抖音精選上均得到廣泛認可和應用。