安卓MVI架构真的来了?动手试着封装吧(三)上

简介: 安卓MVI架构真的来了?动手试着封装吧(三)

本篇内容主要为UI层如何订阅改造之后的viewModel的事件流和状态流


UI状态流的订阅


  为什么要单独写一篇如何订阅Flow(流)的文章呢,首先我们回顾一下官方开发者文档中提供的推荐写法。(代码较多,每一行代码的作用已经用注释写明)


class NewsActivity : AppCompatActivity() {
    private val viewModel: NewsViewModel by viewModels()
    override fun onCreate(savedInstanceState: Bundle?) {
        ...
        //开启协程
        lifecycleScope.launch {
            //控制订阅的生命周期(在UI不可见时取消订阅避免性能浪费)
            repeatOnLifecycle(Lifecycle.State.STARTED) {
                viewModel.uiState
                    //只关注整个状态流中的某个元素
                    .map { it.isFetchingArticles }
                    //防抖,防止其他元素更新导致自身更新
                    .distinctUntilChanged()
                    //收集最终元素
                    .collect { progressBar.isVisible = it }
            }
        }
    }
}

  可见,仅仅是收集一个元素,我们就需要反复书写7行代码,除了我要收集什么元素收集元素之后干什么以外,其余的代码均为模板代码,因此消除这些模板代码是第一业务,毕竟谁也不希望项目中存在一大堆复制粘贴的代码。

  因此,我们的目标是实现一套这样的代码。


//绑定生命周期
viewModel.container.run{
    uiStateFlow.collectState(某个lifecycleOwner) {
        //收集UiState中的某个元素
        collectPartial(某个元素) {
            //做一些事情
        }
        //收集UiState中的某个元素
        collectPartial(某个元素) {
            //做一些事情
        }
        //...收集其余的元素
    }
}

  既然我们是在Flow上面新增逻辑,那么肯定是需要用到kotlin的扩展函数,因此我们给Flow增加一个扩展函数,同时指定必须是UiState的Flow(避免污染到其他非UiState Flow的代码)


fun <T : UiState> Flow<T>.collectState(
    //生命周期持有者,一般是Activity,Fragment之类的
    lifecycleOwner: LifecycleOwner,
    //repeatOnLifecycle方法用
    state: Lifecycle.State = Lifecycle.State.STARTED,
    //State收集器(关键元素),下文会谈到
    action: StateCollector<T>.() -> Unit
) {
    //传递给State收集器,用于开启多个collectPartial()方法
    StateCollector(this@collectState, lifecycleOwner, state).action()
}

  此处并没有给出StateCollector的源码,也许你会很好奇他的作用,其实它的作用并不复杂,只是将collectState()方法中的参数打包在一起,然后通过StateCollector来调用collectPartial()方法来收集UiState中的某个元素。

  此时最大的问题来了,如何在方法中去指定一个Class中的某个元素呢?(下面提供一个data class供读者思考)


data class FriendUiState(
    //朋友列表
    val friendBeanList: List<FriendBean> = emptyList(),
    //是否刷新中
    val refreshing: Boolean = false,
    //是否加载更多
    val loadMore: Boolean = false,
    //是否还有更多数据
    val noMoreData: Boolean = false,
) : UiState

image.png

  答案并不复杂,我们用反射即可,通过kt强大的反射机制,我们可以实现伪代码中的效果。关于kt的反射本文中并不会赘述,你可以通过掘金或者其他网站去自学kt的反射。在继续读下文之前,笔者假设你已经会了kt的反射(至少能看懂代码)

  我们来看看刚才没有给出来的StateCollector的代码


class StateCollector<T : UiState>(
    private val flow: Flow<T>,
    private val lifecycleOwner: LifecycleOwner,
    private val state: Lifecycle.State,
) {
    fun <A> collectPartial(
        prop1: KProperty1<T, A>,
        action: (A) -> Unit
    ) {
        //lifecycleOwner利用开启协程
        lifecycleOwner.lifecycleScope.launch {
            //控制订阅的生命周期
            lifecycleOwner.repeatOnLifecycle(state) {
                    //只关注整个状态流中的某个元素(重点!利用反射机制找出需要的元素)
                    flow.map { prop1.get(it) }
                    //防抖,防止其他元素更新导致自身更新
                    .distinctUntilChanged()
                    //收集元素
                    .collect { partialState ->
                        action(partialState)
                    }
            }
        }
    }

  可见,StateCollector的作用只有1点:消除模板代码。将需要反复重写的逻辑封装在一个收集器的内部,使用了StateCollector之后,我们重新回到最初的伪代码中。


//伪代码
viewModel.container.run{
    uiStateFlow.collectState(某个lifecycleOwner) {
        //收集UiState中的某个元素
        collectPartial(某个元素) {
            //做一些事情
        }
        //收集UiState中的某个元素
        collectPartial(某个元素) {
            //做一些事情
        }
        //...收集其余的元素
    }
}
//封装后的代码
viewModel.container.run {
    uiStateFlow.collectState(this@FriendsActivity2) {
        collectPartial(FriendUiState::friendBeanList) {
            //do someThing
        }
        collectPartial(FriendUiState::refreshing) { refreshing ->
            //do someThing
        }
        collectPartial(FriendUiState::loadMore) { loadMore ->
            //do someThing
        }
        collectPartial(FriendUiState::noMoreData) { noMoreData ->
            //do someThing
        }
    }
}

经过封装后的代码减少了非常多的模板代码,在绑定了lifecycleOwner之后只需要关注两件事:

  1. 收集谁
  2. 收集之后干啥

相关文章
|
1月前
|
设计模式 前端开发 Android开发
Android应用开发中的MVP架构模式解析
【5月更文挑战第25天】本文深入探讨了在Android应用开发中广泛采用的一种设计模式——Model-View-Presenter (MVP)。文章首先概述了MVP架构的基本概念和组件,接着分析了它与传统MVC模式的区别,并详细阐述了如何在实际开发中实现MVP架构。最后,通过一个具体案例,展示了MVP架构如何提高代码的可维护性和可测试性,以及它给开发者带来的其他潜在好处。
|
1月前
|
Android开发
Android 分享机顶盒项目的封装类《GridView》(二)(转)
Android 分享机顶盒项目的封装类《GridView》(二)(转)
24 2
|
8天前
|
前端开发 JavaScript 测试技术
安卓应用开发中的架构模式解析
【6月更文挑战第21天】在软件开发领域,架构模式是设计优雅、高效、可维护应用程序的基石。本文深入探讨了安卓应用开发中常见的架构模式,包括MVC、MVP、MVVM和Clean Architecture,旨在为开发者提供一个清晰的指导,帮助他们选择最适合自己项目的架构风格。通过对比分析这些架构模式的特点、优势以及适用场景,文章揭示了如何根据项目需求和团队能力来采用恰当的架构模式,以实现代码的可维护性、可扩展性和可测试性。
25 7
|
3天前
|
Java API Android开发
技术经验分享:Android源码笔记——Camera系统架构
技术经验分享:Android源码笔记——Camera系统架构
|
11天前
|
移动开发 小程序 安全
基础入门-APP架构&小程序&H5+Vue语言&Web封装&原生开发&Flutter
基础入门-APP架构&小程序&H5+Vue语言&Web封装&原生开发&Flutter
|
16天前
|
前端开发 测试技术 API
探索安卓应用的架构演进:从MVC到MVVM
本篇文章将深入探讨安卓应用开发中的架构演进,特别关注从传统的MVC(Model-View-Controller)到现代流行的MVVM(Model-View-ViewModel)架构的转变。通过对比两种架构的设计理念、实现方式和实际应用案例,解析MVVM在提高代码可维护性和可测试性方面的优势。
23 0
|
18天前
|
Android开发 Kotlin
kotlin安卓开发【Jetpack Compose】:封装SnackBarUtil工具类方便使用
GPT-4o 是一个非常智能的模型,比当前的通义千问最新版本在能力上有显著提升。作者让GPT开发一段代码,功能为在 Kotlin 中使用 Jetpack Compose 框架封装一个 Snackbar 工具类,方便调用
|
1月前
|
架构师 网络协议 算法
Android高级架构师整理面试经历发现?(大厂面经+学习笔记(1)
Android高级架构师整理面试经历发现?(大厂面经+学习笔记(1)
|
1月前
|
前端开发 Android开发
Android架构组件JetPack之DataBinding玩转MVVM开发实战(四)
Android架构组件JetPack之DataBinding玩转MVVM开发实战(四)
Android架构组件JetPack之DataBinding玩转MVVM开发实战(四)
|
1月前
|
XML Java Android开发
Android 分享机顶盒项目的封装类《GridView》(三)(转)
Android 分享机顶盒项目的封装类《GridView》(三)(转)
20 2