BlockFramework —— 客戶端模塊化業(yè)務(wù)開發(fā)框架

前言
在大型 APP 的開發(fā)進(jìn)程中,多個(gè)業(yè)務(wù)方向或團(tuán)隊(duì)共同開發(fā)同一頁(yè)面的現(xiàn)象屢見不鮮。倘若沒有良好的架構(gòu)作為支撐,各業(yè)務(wù)之間的邏輯極易相互耦合,進(jìn)而致使架構(gòu)迅速惡化,這無(wú)疑會(huì)使業(yè)務(wù)開發(fā)與維護(hù)的成本增加。BlockFramework 作為一套客戶端業(yè)務(wù)解耦框架,具備業(yè)務(wù)分層、組裝以及協(xié)同的能力,業(yè)務(wù)方基于此框架能夠輕易實(shí)現(xiàn)業(yè)務(wù)解耦,獨(dú)立開展邏輯迭代,從而提升架構(gòu)的穩(wěn)定性,降低維護(hù)成本,并提高業(yè)務(wù)迭代的效率。BlockFramework 主要有 4 大特性:
- 「清晰的業(yè)務(wù)解耦機(jī)制」:開發(fā)者使用 BlockFramework 能夠輕松地將復(fù)雜的業(yè)務(wù)邏輯拆解成多個(gè)獨(dú)立的子「Block」,實(shí)現(xiàn)代碼上的物理隔離,不同業(yè)務(wù)的開發(fā)者只需要聚焦于所屬業(yè)務(wù)Block開發(fā),降低代碼復(fù)雜度從而提升人效;同時(shí)Block支持跨場(chǎng)景復(fù)用,開發(fā)者可將基礎(chǔ)能力抽離成獨(dú)立的Block后應(yīng)用到不同的場(chǎng)景中,減少冗余代碼,降低維護(hù)成本;
 - 「高性能的UI組裝能力」:BlockFramework基于樹狀結(jié)構(gòu)搭建界面UI,完美契合Android系統(tǒng)的布局樹結(jié)構(gòu),開發(fā)者只需要?jiǎng)?chuàng)建各個(gè)簡(jiǎn)單的子布局Block,然后按照業(yè)務(wù)邏輯構(gòu)建Block之間的父子關(guān)系,便能輕松搭建出一個(gè)復(fù)雜頁(yè)面。同時(shí)相較于常用的UI組裝方式,BlockFramework在UI組裝過程中集成了異步inflate、異步View創(chuàng)建等性能優(yōu)化手段,高效優(yōu)化頁(yè)面性能;
 - 「豐富的通信機(jī)制」:BlockFramework提供了Block之間的多種通信機(jī)制(一對(duì)一、一對(duì)多、多對(duì)一),用于實(shí)現(xiàn)Block之間的聯(lián)動(dòng)交互能力,通信機(jī)制通過接口抽象、事件訂閱/分發(fā)的方式,避免了Block與Block之間直接交互,保證了Block的獨(dú)立性和復(fù)用性;
 - 「統(tǒng)一的開發(fā)范式」:BlockFramework 的接入和開發(fā)流程均提供了標(biāo)準(zhǔn)規(guī)范,使得不同業(yè)務(wù)的開發(fā)者能夠建立統(tǒng)一的開發(fā)認(rèn)知,從而降低跨線研發(fā)成本,提升整體研發(fā)效率。
各種客制化場(chǎng)景,標(biāo)紅區(qū)域?yàn)楦鰾lock: 

BlockFramework已經(jīng)在Github開源,歡迎大家多多支持。開源地址:https://github.com/bytedance/BlockFramework
Block單元
Block是BlockFramework的基本構(gòu)成單元,一個(gè)復(fù)雜頁(yè)面可由多個(gè)Block組裝而成。Block支持UI配置,與安卓View樹結(jié)構(gòu)完美適配,能夠渲染各種不同的場(chǎng)景;同時(shí)Block擁有獨(dú)立的,各Block可以單獨(dú)通過網(wǎng)絡(luò)獲取數(shù)據(jù)、渲染視圖等等。
樹狀管理機(jī)制
Block按照樹形結(jié)構(gòu)進(jìn)行組裝和管理,一個(gè)場(chǎng)景對(duì)應(yīng)一顆Block樹,樹形結(jié)構(gòu)的好處在于:
- 對(duì)于客戶端,通常基于頁(yè)面的布局結(jié)構(gòu)進(jìn)行業(yè)務(wù)開發(fā),而布局結(jié)構(gòu)對(duì)應(yīng)于View樹結(jié)構(gòu),因此,Block構(gòu)建樹狀結(jié)構(gòu)更符合認(rèn)知,通過Block樹便能清晰的看出整個(gè)頁(yè)面的邏輯結(jié)構(gòu);
 - 樹是一種去中心化的結(jié)構(gòu),每個(gè)子Block只能被自己的父Block管理,Manager只需要驅(qū)動(dòng)rootBlock便能操作整顆Block樹,能夠有效降低Manager自身的復(fù)雜度。
 - 樹狀結(jié)構(gòu)易于管理和分析,能夠通過防止樹形結(jié)構(gòu)劣化調(diào)整頁(yè)面的結(jié)構(gòu)劃分,理想狀態(tài)下,一個(gè)場(chǎng)景拆分的Block樹能夠達(dá)到一顆平衡樹結(jié)構(gòu)。
 

Block提供了方式進(jìn)行組裝,業(yè)務(wù)方能直觀的看出各Block之間的父子關(guān)系:
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本身是一個(gè)生命周期單元,遵循Jetpack LifeCycle組件的生命周期節(jié)點(diǎn)設(shè)計(jì),即onCreate() -> onDestory(),開發(fā)者能夠快速上手,同時(shí)易于對(duì)老場(chǎng)景進(jìn)行遷移。
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設(shè)計(jì)圖」

通信機(jī)制
在業(yè)務(wù)場(chǎng)景中,不同的業(yè)務(wù)模塊經(jīng)常需要通信,如處于不同模塊的視圖需要根據(jù)用戶操作發(fā)生一些聯(lián)動(dòng)。在這些情況下,如果讓模塊與模塊直接進(jìn)行依賴,就無(wú)法避免模塊之間的耦合,這樣既無(wú)法保證模塊的獨(dú)立性,也影響可復(fù)用性。因此,Block框架基于SPI協(xié)議和觀察者模式實(shí)現(xiàn)了一套通信機(jī)制,各Block通過發(fā)現(xiàn)服務(wù)和廣播通信,能夠有效降低Block之間的耦合。
Block組內(nèi)通信
Block通過一套MessageCenter機(jī)制實(shí)現(xiàn)內(nèi)部通信,主要包括兩種形式:
- 「一對(duì)一調(diào)用」:基于SPI模式,對(duì)外暴露接口,其他Block可以通過接口獲取其他Block對(duì)外暴露的能力;
 - 「一對(duì)多通信」:基于觀察者模式,可以通過定義Event進(jìn)行事件廣播,所有訂閱該事件的Block默認(rèn)都會(huì)收到該Event;
 

「Block通信范式樹形結(jié)構(gòu)約束」
- 根據(jù)Block的樹形結(jié)構(gòu),對(duì)通信機(jī)制加入樹形結(jié)構(gòu)的約束,即子節(jié)點(diǎn)只能訪問其父節(jié)點(diǎn)的service,如果訪問不到,再向上一級(jí)父Block查詢,直到找到為止,該方式能夠直觀的分析出一個(gè)場(chǎng)景拆分Block后的各Block之間的通信依賴情況。
 
Block組間通信
- 用于實(shí)現(xiàn)Block組件內(nèi)部與外部邏輯交互,通過BlockDepend實(shí)現(xiàn),業(yè)務(wù)場(chǎng)景向Block注入Depend后,在Block內(nèi)部便能隨時(shí)獲取到Depend進(jìn)行通信。
 

高性能特性
Block內(nèi)置了不少高性能特性,相較Android原生的頁(yè)面構(gòu)建機(jī)制,BlockFramework提供了異步組裝View異步數(shù)據(jù)綁定等多個(gè)優(yōu)化手段,旨在更為極致的渲染頁(yè)面。
異步組裝View
Block支持將復(fù)雜頁(yè)面拆分一個(gè)個(gè)小單元,每一個(gè)小單元可對(duì)應(yīng)一處簡(jiǎn)單UI結(jié)構(gòu),如果不做優(yōu)化,這個(gè)Block在inflate和組裝View時(shí)會(huì)默認(rèn)在主線程執(zhí)行,而實(shí)際上,由于每一個(gè)Block的View都是獨(dú)立進(jìn)行inflate,因此,可以各Block的View創(chuàng)建的過程切換到子程序異步進(jìn)行,完成后切換回到主線程組裝View,相較于整體在主線程創(chuàng)建View耗時(shí)更短,經(jīng)過對(duì)比分析,異步組裝View能縮短約20%的耗時(shí)。

異步數(shù)據(jù)綁定
Block提供了異步數(shù)據(jù)綁定邏輯,支持開發(fā)者將耗時(shí)邏輯放到子線程執(zhí)行,并提供了切換回主線程的回調(diào),讓開發(fā)者更方便的執(zhí)行耗時(shí)邏輯。

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()
        }
    }
}結(jié)語(yǔ)
BlockFramework是西瓜視頻團(tuán)隊(duì)從業(yè)務(wù)中沉淀出的組件,經(jīng)過不斷地完善和迭代,目前已經(jīng)成為西瓜視頻詳情頁(yè)、橫屏內(nèi)流、Feed列表、Feed卡片、業(yè)務(wù)播放器等多個(gè)核心場(chǎng)景的底層架構(gòu)基礎(chǔ),經(jīng)過驗(yàn)證,BlockFramework在性能和效率上都取得不錯(cuò)的收益。后續(xù)我們會(huì)在更多的業(yè)務(wù)場(chǎng)景落地,同時(shí)在性能和架構(gòu)上進(jìn)一步優(yōu)化。此外,BlockFramework已經(jīng)推廣到字節(jié)系多個(gè)產(chǎn)品,尤其在西瓜鴻蒙版、鮮時(shí)光、抖音精選上均得到廣泛認(rèn)可和應(yīng)用。















 
 
 

 
 
 
 