浅析Android的MVI框架,卷王的日常

作者: 谁动了我的代码 | 来源:发表于2022-10-09 17:33 被阅读0次

    MVI是什么?

    MVI中 分为UI层、网域层、与数据层,我造个词叫他UDD,其中网域层可有可无,网域层我们最后再来看。我这里不会再一一截图来展示UI层怎么样、数据层怎么样,可直接看官网。(其实相比较于MVVM基本没变化)


    MVI是最近被引入Android的。受Cycle.js框架的思路影响,是基于单向圆柱流的原理进行工作的。框架中主要以下面几个角色为主:

    • Model层:这里的Model不是其他框架中的Model层,在MVI框架中表示存储UI的状态
    • View层:在MVI中View层主要是接口,负责相应UI的状态
    • Intent层:在MVI中Intent(和Android中的Intent不是同一个)主要负责传递UI状态

    MVI数据流

    当用户进行操作时,程序会以Intent的的形式通知Model层,Model层会对这个UI状态做处理在回调View层进行UI的状态刷新,数据永远都是一个环形结构且单向流动,请看下图:


    MVI的优缺点

    优点:

    • UI的所有变化来自State,所以只需聚焦State,架构更简单、易于调试
    • 数据单向流动,很容易对状态变化进行跟踪和回溯
    • State实例都是不可变的,确保线程安全
    • UI只是反应State的变化,没有额外逻辑,可以被轻松替换或复用

    缺点:

    • 所有的操作最终都会转换成State,所以当复杂页面的State容易膨胀
    • State是不变的,每当State需要更新时都要创建新对象替代老对象,这会带来一定内存开销

    MVI架构实战

    总体架构图

    我们使用ViewModel来承载MVI的Model层,总体结构也与MVVM类似,主要区别在于Model与View层交互的部分。

    1. Model层承载UI状态,并暴露出ViewState供View订阅,ViewState是个data class,包含所有页面状态。
    2. View层通过Action更新ViewState,替代MVVM通过调用ViewModel方法交互的方式。

    MVI实例介绍

    添加ViewState与ViewEvent

    ViewState承载页面的所有状态,ViewEvent则是一次性事件,如Toast等,如下所示:

    data class MainViewState(val fetchStatus: FetchStatus, val newsList: List<NewsItem>)  
    
    sealed class MainViewEvent {
        data class ShowSnackbar(val message: String) : MainViewEvent()
        data class ShowToast(val message: String) : MainViewEvent()
    }
    
    1. 我们这里ViewState只定义了两个,一个是请求状态,一个是页面数据。
    2. ViewEvent也很简单,一个简单的密封类,显示Toast与Snackbar。

    ViewState更新

    class MainViewModel : ViewModel() {
        private val _viewStates: MutableLiveData<MainViewState> = MutableLiveData()
        val viewStates = _viewStates.asLiveData()
        private val _viewEvents: SingleLiveEvent<MainViewEvent> = SingleLiveEvent()
        val viewEvents = _viewEvents.asLiveData()
    
        init {
            emit(MainViewState(fetchStatus = FetchStatus.NotFetched, newsList = emptyList()))
        }
    
        private fun fabClicked() {
            count++
            emit(MainViewEvent.ShowToast(message = "Fab clicked count $count"))
        }
    
        private fun emit(state: MainViewState?) {
            _viewStates.value = state
        }
    
        private fun emit(event: MainViewEvent?) {
            _viewEvents.value = event
        }
    }
    

    如上所示:

    1. 我们只需定义ViewState与ViewEvent两个State,后续增加状态时在data class中添加即可,不需要再写模板代码。
    2. ViewEvents是一次性的,通过SingleLiveEvent实现,当然你也可以用Channel当来实现。
    3. 当状态更新时,通过emit来更新状态。

    View监听ViewState

    private fun initViewModel() {
        viewModel.viewStates.observe(this) {
            renderViewState(it)
        }
        viewModel.viewEvents.observe(this) {
            renderViewEvent(it)
        }
    }
    

    如上所示,MVI 使用 ViewState 对 State 集中管理,只需要订阅一个 ViewState 便可获取页面的所有状态,相对 MVVM 减少了不少模板代码。

    View通过Action更新State

    class MainActivity : AppCompatActivity() {
        private fun initView() {
            fabStar.setOnClickListener {
                viewModel.dispatch(MainViewAction.FabClicked)
            }
        }
    }
    class MainViewModel : ViewModel() {
        fun dispatch(action: MainViewAction) =
            reduce(viewStates.value, action)
    
        private fun reduce(state: MainViewState?, viewAction: MainViewAction) {
            when (viewAction) {
                is MainViewAction.NewsItemClicked -> newsItemClicked(viewAction.newsItem)
                MainViewAction.FabClicked -> fabClicked()
                MainViewAction.OnSwipeRefresh -> fetchNews(state)
                MainViewAction.FetchNews -> fetchNews(state)
            }
        }
    }
    

    如上所示,View通过Action与ViewModel交互,通过 Action 通信,有利于 View 与 ViewModel 之间的进一步解耦,同时所有调用以 Action 的形式汇总到一处,也有利于对行为的集中分析和监控。

    Android中的框架有许多最常见的有 MVC、MVP、MVVM 等。其中MVVM更是被官方推荐,成为Android开发中的显学。 不过软件开发中没有银弹,MVVM架构也不是尽善尽美的,在使用过程中也会有一些不太方便之处,而MVI可以很好的解决一部分MVVM的痛点。 更多Android核心技术学习,大家可以前往这里领取一套《Android核心技术手册》进行参考辅导。

    MVI总结

    MVI框架是在MVVM框架的基数上,规定了数据的单项流动,类似于Flutter、Compose等主流框架的写法,非常适合在UI展示的场景。

    每个框架有每个框架的特点和使用场景,找到合适框架才是最好的框架

    相关文章

      网友评论

        本文标题:浅析Android的MVI框架,卷王的日常

        本文链接:https://www.haomeiwen.com/subject/qgogartx.html