列表类产品现在非常多,能够说是10个APP中9个是有列表功用的,今日要说的是视频、直播类切换类型的担任事务解耦。详细事务场景能够用抖音短视频为例,只评论其完结办法。

这种类型的产品一般完结办法有两种。

一、常见此种逻辑的代码完结

1.1 运用ViewPager2 + Fragment

优点:

  1. 模块化: 每个功用都在独立的 Fragment 中完结,使得代码更易于保护和办理。
  2. 复用性: 能够轻松地在不同的页面中重复运用 Fragment,避免了代码的重复编写。
  3. 灵敏性: Fragment 供给了更多的生命周期办法和回调,能够更精细地操控页面的行为和状况。
  4. 易于办理状况: 每个 Fragment 都有自己的生命周期,能够便利地办理页面状况和数据加载。

缺陷:

  1. 内存耗费: 每个 Fragment 都有自己的视图层次结构和生命周期,可能会占用较多的内存,尤其是在包括大量视频或图片的页面。
  2. 功用问题: 在 ViewPager2 中运用 Fragment 可能会存在功用问题,特别是在加载大量页面时,会影响滑动的流畅性。

1.2 运用ViewPager2 + 自界说View

优点:

  1. 轻量级: 自界说 View 能够更轻量地处理页面内容,避免了 Fragment 的杂乱性。
  2. 功用优化: 自界说 View 能够更灵敏地优化制作和布局,提高了页面的烘托功率。
  3. 更小的内存耗费: 自界说 View 能够更精简地办理页面状况,减少了内存占用。
  4. 更灵敏的布局: 自界说 View 供给了更灵敏的布局办法,能够更简单地完结各种杂乱的界面作用。

缺陷:

  1. 杂乱性增加: 自界说 View 的开发相关于 Fragment 更杂乱,需求更多的自界说制作和布局代码。
  2. 可保护性下降: 自界说 View 可能会导致代码结构不够明晰,下降了代码的可读性和可保护性。
  3. 复用性下降: 自界说 View 不像 Fragment 那样简单进行模块化和重用,可能会导致代码冗余和重复编写。

曾经我在直播类产品中运用过第一种办法完结直播间的切换,作用还行,可是也确实遇到了许多坑,不仅是上述的几个缺陷,总归太多笨重,假如有完结这种需求的用第一种办法要三思啊。

二、今日要评论的是这样一个问题

不管运用那种办法,面临如此巨大的事务,每一个Item 的代码应该怎样写? RecyclerView 这个最常用的组件,作者将其写到了一个文件中,有人说聚合性高,写法很牛逼,可是换个人,假如是我写的,他们还会这么说吗?究竟代码还需求给别人看。比方惯例的写法咱们应该是这样的

  1. Activity/Fragment -> 数据填充、特点、触发烘托
  2. ViewPager2 + CustomView -> 惯例列表功用
  3. Custom View中 播放视频、展现图片、用户信息、视频信息、手势处理等等

呈现出来的应该是这样:

简练高效:视频列表规划思路

当然这是是咱们看见的,还有看不见的快进/退、放大、缩小、图文类型、直播类型等等

那这种写法有什么问题呢?

  1. 代码杂乱度增加:一个类中包括大量的事务逻辑和功用会使得代码变得巨大而杂乱,不易于保护和阅览。
  2. 单一责任准则违反:单一责任准则是面向对象编程中的基本准则之一,一个类应该只担任一种类型的责任。将多个不同类型的功用聚合在一个类中,违反了这个准则,会导致代码结构紊乱,难以理解和修正。
  3. 难以测验和调试:功用过于集中的类会导致测验和调试变得困难,由于它们会有过多的依赖和交互。
  4. 耦合度增加:各个功用之间可能会发生较大的耦合,导致代码的灵敏性和可保护性下降。
  5. 可扩展性受限:假如后续需求增加新的功用或修正现有功用,可能会涉及到整个类的修正,增加了开发的风险和本钱。

三、那咱们希望的是什么呢?

当然便是处理上面的这几个问题

3.1 整理一个独立运用的根布局

主意是这样的,为了便利恣意方位的运用,咱们直接自界说一个View,这个View的责任:主要办理一级视频功用,即视频列表的根布局

  1. 列表刷新、加载更多等数据源处理,需求考虑数据的来源
  2. 列表,即ViewPager2 或许可滑动容器的增加
  3. 大局的动画等(比方加载数据时的动画)

3.2 对滑动容器进行独立,让上述的独立布局成为一个能够增加恣意具备上述功用的容器

为了让这个可滑动的容器,责任单一,咱们在此只供给以下功用

  1. 滑动列表初始化
  2. 列表适配器创立及绑定

此刻咱们就具备了两个层级的可滑动的列表

3.3 事务在Adapter中创立,准确来说是增加

这便是一个正常的Adapter,在onCreateViewHolder中进行Item View 的创立,可是假如单纯的创立,不便是上述的问题呈现吗,所以此处需求对ItemView 进行解耦

3.4 解耦ItemView 的担任逻辑(重点在这里)

简练高效:视频列表规划思路

看图的话是不是很简单,不过这种场景中不好处理的问题在于,多个事务可能有相互运用的场景

  1. 一切试图都应该知道有没有链接到对应的ItemView 中
  2. 一切视图事务可能都需求接触事件 比方双击、缩放等
  3. 部分试图可能需求感知播放器的状况以做出自己对应的策略
  4. 一切视图事务都需求知道滑动切换后的数据及动作
  5. 一切的试图关于手势事件的特定场景应该保持一致动作(比方隐藏除视频播放器外的一切视图)等

假如单纯的运用类文件将这些解耦会呈现许多问题,比方上述的问题。 怎样做到上述的这几点呢?怎样优雅的创立这些组件呢,最起码要做到

  1. 组件增加、移除流程有必要明晰
  2. 组件能够感知播放器的各种状况或许订阅状况
  3. 各个组件的操作应该是层级间能够相互影响调用的
  4. 组件间的操作应该能够影响视频播放器器的
  5. 组件的增加应该是可装备的(比方某些场景下不用展现用户信息)

能够分层规划,为了能满足上述的功用

简练高效:视频列表规划思路

类图关系大约如下

简练高效:视频列表规划思路

能够描述为:

  1. VideoLayer 类表明视频图层,它能够经过 bindLayerHost() 办法绑定到 VideoLayerHost,经过 unbindLayerHost() 办法解除绑定。VideoLayer 能够与 VideoView 相关,它的详细功用需求在子类中完结。
  2. VideoLayerHost 类表明视频图层的宿主,能够包括多个 VideoLayer。它能够与 VideoView 相关,经过 attachToVideoView() 办法将自身附加到 VideoView 上。一起,它能够增加和移除 VideoLayerHostListener 监听器,用于监听宿主与 VideoView 的相关状况。
  3. 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)
    }

五、总结

这种规划方案的优势在于供给了更灵敏、可扩展的办法来办理和安排视频播放页面的各个组件,然后下降了代码的杂乱度,提高了代码的可保护性和可读性。以下是对该规划方案的总结:

  1. 模块化和组件化: 经过将视频播放页面的功用拆分成不同的组件,完结了模块化和组件化。每个组件都具有明晰的责任和功用,便于单独开发、测验和保护。
  2. 解耦和灵敏性: 运用图层和宿主的规划形式,完结了各个组件之间的解耦,使得它们能够独立存在而且相互影响。一起,经过笼统工厂形式装备化图层的创立与办理,进一步提高了灵敏性,使得能够根据需求动态地装备和切换不同的图层。
  3. 单一责任准则: 每个组件都遵从单一责任准则,只担任特定的功用和逻辑,使得代码结构明晰,易于理解和修正。
  4. 可扩展性: 经过界说明晰的接口和笼统类,使得能够很简单地扩展和增加新的功用和组件,而不会影响到已有的代码逻辑。
  5. 装备化: 经过笼统工厂形式,将图层的创立和办理装备化,使得能够根据需求动态地装备和切换不同的图层,然后满足不同场景下的需求。

参考: VEVodDemo-android 火山视频UI解耦部分