列表类产品现在非常多,能够说是10个APP中9个是有列表功用的,今日要说的是视频、直播类切换类型的担任事务解耦。详细事务场景能够用抖音短视频为例,只评论其完结办法。
这种类型的产品一般完结办法有两种。
一、常见此种逻辑的代码完结
1.1 运用ViewPager2 + Fragment
优点:
- 模块化: 每个功用都在独立的 Fragment 中完结,使得代码更易于保护和办理。
- 复用性: 能够轻松地在不同的页面中重复运用 Fragment,避免了代码的重复编写。
- 灵敏性: Fragment 供给了更多的生命周期办法和回调,能够更精细地操控页面的行为和状况。
- 易于办理状况: 每个 Fragment 都有自己的生命周期,能够便利地办理页面状况和数据加载。
缺陷:
- 内存耗费: 每个 Fragment 都有自己的视图层次结构和生命周期,可能会占用较多的内存,尤其是在包括大量视频或图片的页面。
- 功用问题: 在 ViewPager2 中运用 Fragment 可能会存在功用问题,特别是在加载大量页面时,会影响滑动的流畅性。
1.2 运用ViewPager2 + 自界说View
优点:
- 轻量级: 自界说 View 能够更轻量地处理页面内容,避免了 Fragment 的杂乱性。
- 功用优化: 自界说 View 能够更灵敏地优化制作和布局,提高了页面的烘托功率。
- 更小的内存耗费: 自界说 View 能够更精简地办理页面状况,减少了内存占用。
- 更灵敏的布局: 自界说 View 供给了更灵敏的布局办法,能够更简单地完结各种杂乱的界面作用。
缺陷:
- 杂乱性增加: 自界说 View 的开发相关于 Fragment 更杂乱,需求更多的自界说制作和布局代码。
- 可保护性下降: 自界说 View 可能会导致代码结构不够明晰,下降了代码的可读性和可保护性。
- 复用性下降: 自界说 View 不像 Fragment 那样简单进行模块化和重用,可能会导致代码冗余和重复编写。
曾经我在直播类产品中运用过第一种办法完结直播间的切换,作用还行,可是也确实遇到了许多坑,不仅是上述的几个缺陷,总归太多笨重,假如有完结这种需求的用第一种办法要三思啊。
二、今日要评论的是这样一个问题
不管运用那种办法,面临如此巨大的事务,每一个Item 的代码应该怎样写? RecyclerView 这个最常用的组件,作者将其写到了一个文件中,有人说聚合性高,写法很牛逼,可是换个人,假如是我写的,他们还会这么说吗?究竟代码还需求给别人看。比方惯例的写法咱们应该是这样的
- Activity/Fragment -> 数据填充、特点、触发烘托
- ViewPager2 + CustomView -> 惯例列表功用
- Custom View中 播放视频、展现图片、用户信息、视频信息、手势处理等等
呈现出来的应该是这样:
当然这是是咱们看见的,还有看不见的快进/退、放大、缩小、图文类型、直播类型等等
那这种写法有什么问题呢?
- 代码杂乱度增加:一个类中包括大量的事务逻辑和功用会使得代码变得巨大而杂乱,不易于保护和阅览。
- 单一责任准则违反:单一责任准则是面向对象编程中的基本准则之一,一个类应该只担任一种类型的责任。将多个不同类型的功用聚合在一个类中,违反了这个准则,会导致代码结构紊乱,难以理解和修正。
- 难以测验和调试:功用过于集中的类会导致测验和调试变得困难,由于它们会有过多的依赖和交互。
- 耦合度增加:各个功用之间可能会发生较大的耦合,导致代码的灵敏性和可保护性下降。
- 可扩展性受限:假如后续需求增加新的功用或修正现有功用,可能会涉及到整个类的修正,增加了开发的风险和本钱。
三、那咱们希望的是什么呢?
当然便是处理上面的这几个问题
3.1 整理一个独立运用的根布局
主意是这样的,为了便利恣意方位的运用,咱们直接自界说一个View,这个View的责任:主要办理一级视频功用,即视频列表的根布局
- 列表刷新、加载更多等数据源处理,需求考虑数据的来源
- 列表,即ViewPager2 或许可滑动容器的增加
- 大局的动画等(比方加载数据时的动画)
3.2 对滑动容器进行独立,让上述的独立布局成为一个能够增加恣意具备上述功用的容器
为了让这个可滑动的容器,责任单一,咱们在此只供给以下功用
- 滑动列表初始化
- 列表适配器创立及绑定
此刻咱们就具备了两个层级的可滑动的列表
3.3 事务在Adapter中创立,准确来说是增加
这便是一个正常的Adapter,在onCreateViewHolder中进行Item View 的创立,可是假如单纯的创立,不便是上述的问题呈现吗,所以此处需求对ItemView 进行解耦
3.4 解耦ItemView 的担任逻辑(重点在这里)
看图的话是不是很简单,不过这种场景中不好处理的问题在于,多个事务可能有相互运用的场景
- 一切试图都应该知道有没有链接到对应的ItemView 中
- 一切视图事务可能都需求接触事件 比方双击、缩放等
- 部分试图可能需求感知播放器的状况以做出自己对应的策略
- 一切视图事务都需求知道滑动切换后的数据及动作
- 一切的试图关于手势事件的特定场景应该保持一致动作(比方隐藏除视频播放器外的一切视图)等
假如单纯的运用类文件将这些解耦会呈现许多问题,比方上述的问题。 怎样做到上述的这几点呢?怎样优雅的创立这些组件呢,最起码要做到
- 组件增加、移除流程有必要明晰
- 组件能够感知播放器的各种状况或许订阅状况
- 各个组件的操作应该是层级间能够相互影响调用的
- 组件间的操作应该能够影响视频播放器器的
- 组件的增加应该是可装备的(比方某些场景下不用展现用户信息)
能够分层规划,为了能满足上述的功用
类图关系大约如下
能够描述为:
-
VideoLayer
类表明视频图层,它能够经过bindLayerHost()
办法绑定到VideoLayerHost
,经过unbindLayerHost()
办法解除绑定。VideoLayer
能够与VideoView
相关,它的详细功用需求在子类中完结。 -
VideoLayerHost
类表明视频图层的宿主,能够包括多个VideoLayer
。它能够与VideoView
相关,经过attachToVideoView()
办法将自身附加到VideoView
上。一起,它能够增加和移除VideoLayerHostListener
监听器,用于监听宿主与VideoView
的相关状况。 -
VideoView
类表明视频视图,它能够包括一个VideoLayerHost
作为其宿主。能够经过bindLayerHost()
办法将VideoLayerHost
绑定到当时的VideoView
上。
这样一来,能够经过VideoLayerHost来办理VideoLayer 的增加删去,并经过它联系起来这个视图层的运作,在运用过程中,能够用以下流程描述增加一个ItemView 的流程及其原理
3.5 笼统工厂形式装备化图层的创立与办理
在恣意运用方位可进行自界说笼统工厂来改变图层
class MyVideoViewFactory : VideoViewFactory {
override fun createVideoView(context: Context): VideoView {
val videoView = VideoView(context)
val layerHost = VideoLayerHost(context)
val videoInfoLayer = VideoInfoLayer()
layerHost.addLayer(videoInfoLayer)
layerHost.attachToVideoView(videoView)
videoView.setBackgroundColor(ContextCompat.getColor(context, R.color.default_bg))
return videoView
}
}
四、运用流程 部分代码
4.1 在目标页面进行视图绑定
private fun testArchitecture() {
val videoItems = mutableListOf<VideoPageItem>()
testData(videoItems)
// 运用前根据装备指定图层
// VideoViewFactory.setVideoViewFactory(MyVideoViewFactory())
val videoSceneView = VideoSceneView(this)
.apply {
videoPageView.setLifeCycle(lifecycle)
videoPageView.setItems(videoItems)
}
setContentView(videoSceneView)
}
五、总结
这种规划方案的优势在于供给了更灵敏、可扩展的办法来办理和安排视频播放页面的各个组件,然后下降了代码的杂乱度,提高了代码的可保护性和可读性。以下是对该规划方案的总结:
- 模块化和组件化: 经过将视频播放页面的功用拆分成不同的组件,完结了模块化和组件化。每个组件都具有明晰的责任和功用,便于单独开发、测验和保护。
- 解耦和灵敏性: 运用图层和宿主的规划形式,完结了各个组件之间的解耦,使得它们能够独立存在而且相互影响。一起,经过笼统工厂形式装备化图层的创立与办理,进一步提高了灵敏性,使得能够根据需求动态地装备和切换不同的图层。
- 单一责任准则: 每个组件都遵从单一责任准则,只担任特定的功用和逻辑,使得代码结构明晰,易于理解和修正。
- 可扩展性: 经过界说明晰的接口和笼统类,使得能够很简单地扩展和增加新的功用和组件,而不会影响到已有的代码逻辑。
- 装备化: 经过笼统工厂形式,将图层的创立和办理装备化,使得能够根据需求动态地装备和切换不同的图层,然后满足不同场景下的需求。
参考: VEVodDemo-android 火山视频UI解耦部分