哔哩哔哩技术

B站直播间基于视图交互的架构演进

本期作者

杜峰

哔哩哔哩资深开发工程师

背景

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 数据使用场景

数据使用分为三个场景: 初始化数据,交互数据,对外提供数据

初始化数据
  1. 一个业务的初始化一般处于房间加载的某个任务中

  2. 业务初始化,由当前任务提供该阶段可以访问的数据,作为初始化数据

  3. 初始化数据会转化为 业务专有的数据结构(图中Data) ,供内部逻辑、视图使用和管理

交互数据
  1. 一个房间所有业务初始化完成后,如果没后续的交互,理论上是完全静止的,任何改变当前直播间的动作都可以看做是 一个交互 ,而每个交互都会带上一些数据
  2. 用户每次对业务View的点击、滑动等都会产生一些事件并带上相应的数据,这些事件可能直接在View层就已经消费掉,也可能会触发一系列的逻辑交互

  3. Socket和Http的响应作为另一类交互数据的来源,由Service层向上通知到各个业务逻辑层,业务逻辑需要监听这些数据变化做相应处理

  4. 此外每个业务都可能会关心其他业务的改变,这些往往改变也会带来一些数据,依据这些数据业务可能需要对自己的逻辑和View进行相应的操作


对外提供数据
  1. 在交互数据里有提到关心其他业务的变化,这部分的变化应该由每个业务在API中决定暴露那些事件和数据供外部使用

  2. 如果关心某个业务的变化,可以通过ServiceManager获取对应业务的API,通过关心业务API暴露的方法来获取、订阅数据

    a. provideData类型方法:对外暴露提供数据的方法,由类型方法提供的数据表示,该业务可以对外提供的数据 b. notifyChange类型方法:有数据变化需要对外通知时对外暴露的方法,其他业务通过该类型方法可以订阅相应的变化通知
  3. 每个业务在提供数据时应该考虑清楚需要暴露的数据, 不可直接暴露Data给外部使用
  4. 每个业务在接收到其他业务的变化通知时,应该在对应的处理里消费掉传过来的数据,不要持有该部分数据


2.2 数据的流向

  1. 进入直播间时会请求一组初始化接口,响应数据将会由数据分发器管理,分发到各个业务的Services,不同各个业务拿到各自关心的数据后放到各自的businessData中

  2. 各业务的Service中将会管理业务所持有的数据,ViewModel想要获取或改变某个数据时,需要持有对应业务的Service

  3. ViewModel中将各业务的原始数据组合处理后通过LiveData通知对应的View,View可以通过ViewModel对原始数据进行修改

  4. View间的事件(纯粹的UI变化)将由ViewEventManager作为通道进行传递,传递过程中的数据为一次性数据,不可作为该次事件处理外的逻辑数据使用


03 直播间的视图结构和业务区域

3.1 直播间的结构和区域划分

  1. 在加入上下滑逻辑之前,房间的概念与整个Activity等价,一个房间在Activity被销毁时释放所有资源

  2. 在加入上下滑逻辑后,房间的概念变为滑动组件中的一个Item,一个房间在Item被划走时释放所有资源,为了更好的理解业务运行逻辑,我们根据直播间的视图结构对业务区域进行了划分

    a. 容器区域(Global) 包含滑动组件和DIALOG业务层(目前仅话题和各种引导用到),在进房时创建该区域

    b. 房间区域(Room) 包含房间业务层和播放器业务层,这两部分视图均挂载在滑动组件的RoomItem上,在滑动停止时创建该区域

  3. 在用户执行的滑动操作停止后会释放上一个RoomItem的资源,并重新创建 房间区域 挂载到停止后的RoomItem根布局上,而 容器区域 中的资源仍然随Activity的销毁而销毁,当前的 房间区域 也会随 容器区域 的销毁而销毁

  4. 业务仅需要声明自己属于Global还是Room区域,并在创建、销毁的回调中编写逻辑,而不需要关心自己何时被创建和销毁


3.2 按区域划分加载流程

  1. 以构建item中房间容器的时机为分割点,之前的加载流程属于 容器区域 ,之后的加载流程属于 房间区域

  2. 房间初始化接口请求(P0、P1接口)比较特殊,请求时机以及请求的上游处理逻辑属于 容器区域 ,但是接口响应数据的处理逻辑属于 房间区域

  3. 在直播间销毁的流程中,在容器销毁流程和房间销毁流程中都需要销毁的逻辑,归为 房间区域 管理,仅在容器销毁流程中销毁的逻辑归 容器区域 管理


04 架构演进中的一些思考

1. 架构最后是为业务需求场景服务的,那它也要顺应业务的变化而适时调整。来B站直播的期间经历了直播间从不能滑动到可以上下滑,从老直播间为主到以新版直播间为主,整个产品交互形态发生了巨大变化,新的架构演进方向往往取决于对新业务形态的认知。

2. 随着业务的不断发展和改变以及组织架构的调整,因为赶工期、图方便而设计不合理但刚好能用的代码会越来越多,原先用起来很顺畅的架构必定会慢慢腐烂变质,一直修修补补只是在掩饰问题和推迟问题的爆发,作为一线开发我完全可以理解开发时的内心想法:

  • 别人都这么写,就算是不合理,跟着也总不会错

  • 时间不够了,这坨代码真烂,但我只是来改点小功能,等谁改不动了谁去改

  • 现有的架构根本没考虑到我这种场景,先随便找个地方放着,能实现需求再说

3. 基于以上思考,我认为架构演进的目的主要有两个:

  • 打破团队的不满:打破保守的做法,要积极面对不合理的地方。团队不定期需要着手开启重构,将大家平日对代码的不满释放出来。整理直播间老大难的历史债,将架构的腐化(效率降低、抱怨上升)转化为架构优化的动力。

  • 团队意识的培养:培养全员架构的意识,架构演进的过程中会牵扯众多模块的重构,在各个模块重构的过程中传达架构的思想、形成团队共识,形成“人人都是架构师”的氛围。

我们为大家准备了热招岗位
扫码投递 ,极速处理!

我们感兴趣的技能点都在这里↓

期待各路大神加入


更多技术岗位,可以直接搜索关键词~ 全站“ 技术类 ”岗位大合集系列↓