B站直播間基於檢視互動的架構演進

陶然陶然發表於2022-11-01

   背景

  1. B站的直播間作為整個APP中互動最為複雜的單頁面之一,其承擔的業務量已經不亞於一個小型APP。對比APP的結構會發現許多相同處,但與組成APP的各個獨立Activity不同,直播間由各個獨立的檢視組成。  

  從APP維度看每個Activity是一個業務單元,類比直播間維度每個直播間中的View是一個業務單元。

  2. 業務邏輯基於MVVM的設計分為三層(Service即M層),理想狀態下各個業務間的互動是內聚的,各業務間不會感知到其他業務的存在,View顯示需要的資料和狀態都由各自對應的ViewModel提供。  

  3. 現實情況中業務互動並沒有那麼理想,直播間中的一個View顯示的資料會受到其他業務的資料、狀態影響,因此一個View除了需要處理自己內聚的邏輯為還需要關心其他View的資料變化。

   01 直播間業務互動現狀

  1.1 現有互動邏輯

  直播間是一種單頁面強互動型業務場景,一個業務就經常需要會關心其他業務的狀態,因此垂直方向擴充業務場景就會很多,直播間中的業務幾乎都是在垂直螢幕方向上進行擴充的,產品在新增業務時往往會將重要的業務放在更顯眼的地方,因此需要儘量使重要的業務不被遮擋。

  然而,直播間的檢視又不是一成不變的,與常規頁面面對的業務場景不同,直播間的檢視除了需要響應使用者自己的操作外,還需要根據主播和其他正在看直播的使用者操作展示和改變檢視,為了保證整體展示邏輯沒問題經常會有檢視聯動的需求。

  下圖列舉了部分直播間業務的構建位置和層級關係,按層劃分類似的檢視直播間中有60多個:  

  現存的設計將大部分業務邏輯集中在ViewModel中處理,因為有著LiveData的存在,資料變化的監聽在ViewModel和View間變得容易。

  當其他ViewModel已經存在自己View關心的LiveData或呼叫方法時,開發者很自然的會去引用一個現有的其他ViewModel來觀察他持有的LiveData或呼叫其方法。  

  1.2 現有互動邏輯帶來的問題

  不規範的LiveData的使用和糅雜在一起的業務邏輯導致了ViewModel引用的濫用,使得View間的耦合愈發嚴重,下圖是現有直播間ViewModel的引用關係:  

  直播間內日益複雜的業務會進一步加重View之間的耦合,在分析了上圖中的引用關係後,會發現目前之所以會出現View引用其他業務的ViewModel的場景,主要有兩個原因:

  1. 與View對應的ViewModel無法提供需要的資料,其他Viewmodel持有需要的資料

  2. View的某個操作或資料改變需要告知其他業務,其他Viewmodel包含需要呼叫的方法

  直播間內日益複雜的業務會進一步加重View之間的耦合,特別是在新增的業務對老業務有改動時,開發人員慣性的去尋找有沒有現成的邏輯處理,如果有就會想辦法複用,而現存的設計將大部分業務邏輯集中在ViewModel中處理,就必定會導致ViewModel引用的不可控。

  1.3 問題的分析

  直播間各業務引用關係錯亂只是表象,最直接的原因就是業務資料的訪問的不規範,錯綜複雜的引用關係會加重業務間的耦合情況,耦合的業務邏輯又會增加業務載入流程和資料分發的複雜度,週而復始,形成了惡性迴圈。  

  針對以上問題打破惡性迴圈,我們透過指令碼分析了直播間內60+業務模組,列出了1400+個引用ViewModel的具體使用場景,並且整理了的理想中的資料提供方作為後續改造的參考:  

   02 基於檢視劃分的業務資料

  直播間中的業務使用MVVM的結構構建,我們提供了一套統一的構建模板來構建和管理各層邏輯,單個業務中每層有各自維護的資料和狀態資訊,這些資料禁止躍層訪問,並跟隨各層的生命週期建立和銷燬。  

  2.1 資料使用場景

  資料使用分為三個場景:初始化資料,互動資料,對外提供資料  

  初始化資料

  一個業務的初始化一般處於房間載入的某個任務中

  業務初始化,由當前任務提供該階段可以訪問的資料,作為初始化資料

  初始化資料會轉化為業務專有的資料結構(圖中Data),供內部邏輯、檢視使用和管理

  互動資料

  一個房間所有業務初始化完成後,如果沒後續的互動,理論上是完全靜止的,任何改變當前直播間的動作都可以看做是一個互動,而每個互動都會帶上一些資料

  使用者每次對業務View的點選、滑動等都會產生一些事件並帶上相應的資料,這些事件可能直接在View層就已經消費掉,也可能會觸發一系列的邏輯互動

  Socket和Http的響應作為另一類互動資料的來源,由Service層向上通知到各個業務邏輯層,業務邏輯需要監聽這些資料變化做相應處理

  此外每個業務都可能會關心其他業務的改變,這些往往改變也會帶來一些資料,依據這些資料業務可能需要對自己的邏輯和View進行相應的操作

  對外提供資料

  在互動資料裡有提到關心其他業務的變化,這部分的變化應該由每個業務在API中決定暴露那些事件和資料供外部使用

  如果關心某個業務的變化,可以透過ServiceManager獲取對應業務的API,透過關心業務API暴露的方法來獲取、訂閱資料

  a. provideData型別方法:對外暴露提供資料的方法,由型別方法提供的資料表示,該業務可以對外提供的資料

  b. notifyChange型別方法:有資料變化需要對外通知時對外暴露的方法,其他業務透過該型別方法可以訂閱相應的變化通知

  每個業務在提供資料時應該考慮清楚需要暴露的資料,不可直接暴露Data給外部使用

  每個業務在接收到其他業務的變化通知時,應該在對應的處理裡消費掉傳過來的資料,不要持有該部分資料

  2.2 資料的流向

  進入直播間時會請求一組初始化介面,響應資料將會由資料分發器管理,分發到各個業務的Services,不同各個業務拿到各自關心的資料後放到各自的businessData中

  各業務的Service中將會管理業務所持有的資料,ViewModel想要獲取或改變某個資料時,需要持有對應業務的Service

  ViewModel中將各業務的原始資料組合處理後透過LiveData通知對應的View,View可以透過ViewModel對原始資料進行修改

  View間的事件(純粹的UI變化)將由ViewEventManager作為通道進行傳遞,傳遞過程中的資料為一次性資料,不可作為該次事件處理外的邏輯資料使用  

   03 直播間的檢視結構和業務區域

  3.1 直播間的結構和區域劃分

  在加入上下滑邏輯之前,房間的概念與整個Activity等價,一個房間在Activity被銷燬時釋放所有資源

  在加入上下滑邏輯後,房間的概念變為滑動元件中的一個Item,一個房間在Item被划走時釋放所有資源,為了更好的理解業務執行邏輯,我們根據直播間的檢視結構對業務區域進行了劃分

  a. 容器區域(Global)包含滑動元件和DIALOG業務層(目前僅話題和各種引導用到),在進房時建立該區域

  b. 房間區域(Room)包含房間業務層和播放器業務層,這兩部分檢視均掛載在滑動元件的RoomItem上,在滑動停止時建立該區域

  在使用者執行的滑動操作停止後會釋放上一個RoomItem的資源,並重新建立房間區域掛載到停止後的RoomItem根佈局上,而容器區域中的資源仍然隨Activity的銷燬而銷燬,當前的房間區域也會隨容器區域的銷燬而銷燬

  業務僅需要宣告自己屬於Global還是Room區域,並在建立、銷燬的回撥中編寫邏輯,而不需要關心自己何時被建立和銷燬  

  3.2 按區域劃分載入流程

  以構建item中房間容器的時機為分割點,之前的載入流程屬於容器區域,之後的載入流程屬於房間區域

  房間初始化介面請求(P0、P1介面)比較特殊,請求時機以及請求的上游處理邏輯屬於容器區域,但是介面響應資料的處理邏輯屬於房間區域

  在直播間銷燬的流程中,在容器銷燬流程和房間銷燬流程中都需要銷燬的邏輯,歸為房間區域管理,僅在容器銷燬流程中銷燬的邏輯歸容器區域管理  

   04 架構演進中的一些思考

  1. 架構最後是為業務需求場景服務的,那它也要順應業務的變化而適時調整。來B站直播的期間經歷了直播間從不能滑動到可以上下滑,從老直播間為主到以新版直播間為主,整個產品互動形態發生了巨大變化,新的架構演進方向往往取決於對新業務形態的認知。

  2. 隨著業務的不斷髮展和改變以及組織架構的調整,因為趕工期、圖方便而設計不合理但剛好能用的程式碼會越來越多,原先用起來很順暢的架構必定會慢慢腐爛變質,一直修修補補只是在掩飾問題和推遲問題的爆發,作為一線開發我完全可以理解開發時的內心想法:

  別人都這麼寫,就算是不合理,跟著也總不會錯

  時間不夠了,這坨程式碼真爛,但我只是來改點小功能,等誰改不動了誰去改

  現有的架構根本沒考慮到我這種場景,先隨便找個地方放著,能實現需求再說

  3. 基於以上思考,我認為架構演進的目的主要有兩個:

  打破團隊的不滿:打破保守的做法,要積極面對不合理的地方。團隊不定期需要著手開啟重構,將大家平日對程式碼的不滿釋放出來。整理直播間老大難的歷史債,將架構的腐化(效率降低、抱怨上升)轉化為架構最佳化的動力。

  團隊意識的培養:培養全員架構的意識,架構演進的過程中會牽扯眾多模組的重構,在各個模組重構的過程中傳達架構的思想、形成團隊共識,形成“人人都是架構師”的氛圍。

來自 “ 嗶哩嗶哩技術 ”, 原文作者:杜峰;原文連結:http://server.it168.com/a2022/1031/6771/000006771347.shtml,如有侵權,請聯絡管理員刪除。

相關文章