Google 推荐使用 MVI 架构?卷起来了~

前言

前段时间写了一些介绍MVI架构的文章,不过软件开发上没有最好的架构,只有最合适的架构,同时众所周知,Google推荐的是MVVM架构elementary是什么意思。相信很多人都会有疑问,我为什么不使用官方推荐的MVVM,而要用你说的这个什么elements中文翻译MVI架构呢?
不过我这几天查看Android的应用架构指南,发现谷歌推荐的最佳实践已经变成了单向数据流动 + 状态集中管理,这不就是MVI架构吗? 看起来Google已经开始推荐使用MVI架构了,大家也有必要开始了解一下Android应用架构指南的最新版本了~

本文主要基于A通信技术专业nd协程roid应用架构指南,感兴趣的也可以直接查看原文

总体架构

两个架构原则

Android的架构设计原则主要有两个

分离关注点

要遵循的最重要的原则是分离关注点。一种常见的错误是在一携程旅行app官方下载ActivityFragment 中编写所elementui有代码。这些基于界面的类应仅包含处理elements中文翻译界面和操作系统交互的逻辑。 总得来说,ActivityFragment中的代码应该尽量精简,尽量将业务逻辑迁移到其它层

通过数据驱动界面

另一个重要原则是您应该通过数据驱动界面(最好是持久性模型)。数据模型独立于应用中的界面元素和其他组件。
这意味着它们与界面和应用组件的生命周期没有关联,但仍会在操作系统决定从内存中移除应用的进程时被销毁。
数据模型与界面元素,生命周期解耦,因此方便复用携程电话,同时便于测试,更加稳定可靠。

推荐的应用架构

基于上一测试抑郁程度的问卷部分提到的常见架构原则,每个应用应至少有两个层:

  • 界面层 – 在屏幕上显示应用数据。
  • 数据层 – 提供所需要的应用数据。

您可以额外添加一个名为“网域层”的架构层,以简化和复用使用界面层与数据层之间的交互

Google 推荐使用 MVI 架构?卷起来了~

如上所示,各层之间的依赖关系是单通信达向依赖的,网域层,数据层不依赖于界面层

界面层

界面的作用是在屏幕elementary上显示应用数据,elementui并响应用户的点击。每当数据发生变化时,无论是因为用户互动(例如按了某个按钮),还是因为外部输入(例如网络响应),element是什么意思界面都应随之更新,以反映这些变化。
不过,从数据层获取的应用数据的格式通常不同于UI需要展示的数据的格式,因此我们需要将数据层数据转化为页面的状态
因此界面层一般分为两部分,即UI层与State HolderState Holder的角色一般mvvm指的是ViewModel承担

Google 推荐使用 MVI 架构?卷起来了~

数据层的作用是存储和管理应用数据,以及提供对应用数据的访问权测试抑郁程度的问卷限,因此界面层必须执行以下步骤:

  1. 获取应用数据,并将其转换为UI可以轻松呈现的UI State
  2. 订阅UI State,当页面状态发生改变时刷新UI
  3. 接收用户的输入事件,并根据相应的事件进行处理,从而刷新UI State
  4. 根据需要重复携程网站官网第 1-3 步。

主要是一个单向数据流动,如下图所示:

Google 推荐使用 MVI 架构?卷起来了~

因此界面层主要需要做以下工作:

  1. 如何定义UI State
  2. 如何使用单向数据流 (UDF),作为提供和管理UI State的方式。
  3. 如何暴露与更新UI State
  4. 如何订阅UI State

如何定义UI State

如果我们要实现一个新闻列表界面,我们该怎么定义UI Selementary是什么意思tate呢?我们将界面测试你适合学心理学吗需要的所有状态都封装在一个data class中。mvvm指的是
与之前的M协程客服电话VVM模式的主要区别之一也在这里,即之前通常是一个State对应一个LiveData,而MVI架构则强调对UI State的集中管理

data class NewsUiState(
    val isSignedIn: Boolean = false,
    val isPremium: Boolean = false,
    val newsItems: List<NewsItemUiState> = listOf(),
    val userMessages: List<Message> = listOf()
)
data class NewsItemUiState(
    val title: String,
    val body: String,
    val bookmarked: Boolean = false,
    ...
)

以上示例中的UI State定义是不可变的。这样的主要好处是,不可变对象可保证即时提供应用的状态。这样一来,UI便可专注于发挥单一作用:读取UI StaElementte并相应地更新其UI通信技术专业素。因此,切勿直接在UI中修elementsUI State。违反这个原则会elements硬盘导致同一条信息有多个可信来源,从而导致数据不一致的问题。

例如,如上中来自UI StateNewsItemUiState对象中的bookmarked标记在Activity类中elementary翻译已更新,那么该标记会与数据层展开竞争,从而产生多数据源的mvvm原理问题。

UI State集中管理的优缺点

MVVM中我们通常是多个数据流,即一个State对应一个LiveData,而MVI中则是单个数据流。两者各有什么优缺点?
单个数据流的优点主要在于方便,减少模板代码,添加一个状态只mvvm模型需要给data class添加一个属性即可,可以有效地降低通信工程专业ViewModelView通信成本
同时UI State集中管理可以轻松地实现类似MediatorLiveData的效果,比如可能只有在用户已登录并测试抑郁症的20道题且是付费新闻服务订阅者时,您才需要显示书签按钮。您可以按如下方式定义UI Smvvm原理tate

data class NewsUiState(
    val isSignedIn: Boolean = false,
    val isPremium: Boolean = false,
    val newsItems: List<NewsItemUiState> = listOf()
){
	val canBookmarkNews: Boolean get() = isSignedIn && isPremium
}

如上所示,书签的可见性是其它两个属性的派生属性,其它两个属性发生变化时,canBookmarkNews也会自动携程变化,当我们需要实现书签的可见与隐藏逻辑,只需要携程网飞机票预订官网订阅canBookmarkNews即可,这样可以轻松实现类似MediatorLiveData的效果,但是远比MediatorLiveData要简单

当然,UI State集中管理也会有一些问题:

  • 不相关的数据类型:UI所需的某些状态可能是完全相互独立的。mvvm框架在此类情况下,将这些不同的状态捆绑在一起的代价可能会超过测试其优势,尤其是当其中某个状态的更新频率高于其他状态的更新频率时。
  • UiState diffingUiState 对象中通信技术的字段越多,数据mvvm模型流就越有可能因为其中一个字段被更新而发通信人家园出。由于视图没有 diffing 机制来了解连续发出的数据流是否通信大数据行程卡相同,因测试智商此每次发出都会导致视图更新。当然,携程app我们可以对 LiveDataFlow使用 distinctUntilChanged() 等方法来elementui实现局部刷新,从而解决这个问题

使用单向数据流管理ElementUI State

上文提到,为了保证UI中不能修改状态,U测试智商I State中的元素都是不可变的,那么如何更新UI State呢?mvvm原理
我们一般使用ViewModel作为UI State的容器,因此响应用户输入更新UI State主要分为以下几步:

  1. ViewModel 会存储并公开UI StateUI State是经过Vielements硬盘ewModel转换的应用数据。
  2. UI层会向ViewModel发送用户事件通知。
  3. ViewModel会处理用户操作并更新UI State
  4. 更新后的状态将反馈给UI以进行呈现。
  5. 系统会对导致状态更改的所有事件重复上述操作。

举个例子,如果用户需要给新闻列表加个书签,携程旅行app官方下载那么就需要将事件传递给ViewModel,然后ViewModel更新UI State(中间可能有数据层的更新),UI层订阅UI State订响应刷新,从而完成测试用例页面刷新,如下图所示:

Google 推荐使用 MVI 架构?卷起来了~

为什么使用单向数据流动?

单向数据流动可以实现关注点分离原则,它可以将状态变化来源位置、转换位置以及携程网官网最终使用位置进行分离。
这种分离可让UI只发挥其携程app名称所mvvm框架表明的作用:通过观察UI State变化Element来显示页面信息,并将用户输入传递测试抑郁程度的问卷ViewModel测试工程师实现状态刷新。

换句话说,单向数据流动有助于实现以下几点:

  1. mvvm模式和mvc的区别据一致性。界面只有一个可信来源。
  2. 可测试性。状态来源是独立的,因此可独立于界面进行测试。
  3. 可维护性。状态的更改遵循明确定义的模式,测试工程师即状态更element是什么意思改是用户事件及其数据拉取来源共同作用的结果。

测试露与更新UI State

定义好UI State并确定如何管理携程网飞机票预订官网相应状态后,下一步是将提供的状态发送给界面。我们可以使用LiveData或者StateFlowUI State转化为数据流并暴露给UI
为了保证不能在UI中修改状态,我们应该定义一个可变的StateFlow与一个不可变的StateFl通信大数据行程卡ow,如下所示:

class NewsViewModel(...) : ViewModel() {
    private val _uiState = MutableStateFlow(NewsUiState())
    val uiState: StateFlow<NewsUiState> = _uiState.asStateFlow()
    ...
}

这样一来,UI层可以订阅状态,而ViewModel也可以修改状态通信地址,以需要执行异步操作的情况为例,可以使用viewModelScope启动协程,并且可以在操作测试用例完成时更新状态。

class NewsViewModel(
    private val repository: NewsRepository,
    ...
) : ViewModel() {
    private val _uiState = MutableStateFlow(NewsUiState())
    val uiState: StateFlow<NewsUiState> = _uiState.asStateFlow()
    private var fetchJob: Job? = null
    fun fetchArticles(category: String) {
        fetchJob?.cancel()
        fetchJob = viewModelScope.launch {
            try {
                val newsItems = repository.newsItemsForCategory(category)
                _uiState.update {
                    it.copy(newsItems = newsItems)
                }
            } catch (ioe: IOException) {
                // Handle the error and notify the notify the UI when appropriate.
                _uiState.update {
                    val messages = getMessagesFromThrowable(ioe)
                    it.copy(userMessages = messages)
                 }
            }
        }
    }
}

在上面的示例中,NewsViewModel 类会尝试进行网络请求,然后更新UI测试抑郁程度的问卷 State,然后UI层可以对其做出适当反应测试手机是否被监控

订阅UI State

订阅UI State很简单,只需要在UI层观察并刷新UI即可

class NewsActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        lifecycleScope.launch {
            repeatOnLifecycle(Lifecycle.State.STARTED) {
                viewModel.uiState.collect {
                    // Update UI elements
                }
            }
        }
    }
}

UI State实现局部刷新

因为MVI架构下实现了UI State的集中管理,因此更新一个属性就会导致UI State的更新测试,那么在这种情况下怎么实现局部刷新呢?
我们可以利用distin携程网上订票飞机ctUntilChanged实现,distinctUntilChanged只有在值发生变化了之后才会回调刷新,相当于对属性做了一个防抖,因此我们可以实现局部刷新,使用方式如下所示

class NewsActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        lifecycleScope.launch {
            repeatOnLifecycle(Lifecycle.State.STARTED) {
                // Bind the visibility of the progressBar to the state
                // of isFetchingArticles.
                viewModel.uiState
                    .map { it.isFetchingArticles }
                    .distinctUntilChanged()
                    .collect { progressBar.isVisible = it }
            }
        }
    }
}

当然Element我们也可以对其进行一定的封装,给Flow或者LiveData添加一测试抑郁症的20道题个扩展函数,令其通信地址支持监听属性即可,使用方式如下所示

class MainActivity : AppCompatActivity() {
	private fun initViewModel() {
        viewModel.viewStates.run {
            //监听newsList
            observeState(this@MainActivity, MainViewState::newsList) {
                newsRvAdapter.submitList(it)
            }
            //监听网络状态
            observeState(this@MainActivity, MainViewState::fetchStatus) {
                //..
            }
        }
    }
}

关于MVI架构下支elements持属协程客服电话性监听,更加详细地内容可见:MVI 架构更佳实践:支持 LiveData 属性携程网上订票飞机监听

网域层

网域层是位于界面层和数据层之间的MVVM可选层。

Google 推荐使用 MVI 架构?卷起来了~
网域层负责通信行程卡封装复杂的业务逻辑,或者由多个ViewModel重复使用的简单业务逻辑。此层是可选的,因为并非所有应用都有这类需求。因此,您应仅在需要时使用该层。
网域层具有以下优势:

  1. 避免代码重复。
  2. 改善使用网域层类的类的可读性。
  3. 改善应用的可测试性。
  4. 让您能够划分好职责,从而避免出现大型类。

我感觉对于常见的APP,网域层携程app似乎并没通信人家园有必要,对于ViewModel重复的逻辑,使用util来说一般就已足够
或许网域层适用于特别大型的项目吧,各位可根据自己的需求选用,关于携程机票网域层的详细信息可见:developer.android.com/jetpack/gui…

数据层

数据层主要负责获取与处理数据的逻辑,数据层mvvm的理解由多个Repository组成,其中每个Repository可包含零到多个Data Source。您应该为应用处理的每种不同类型的数据创建一个Repository类。例携程电话如,您可以为与电影相关的数据创建 MoviesRepos测试你适合学心理学吗itory 类,或者为与付测试你适合学心理学吗款相关的数据创建 PaymentsRepository 类。当然为了携程网上订票飞机方便,针对只有一个数据源的Repository,也可以将数据源的代码也写在Repository,后续有多个数据源时再做拆分

Google 推荐使用 MVI 架构?卷起来了~
数据层跟之前的MVVM架构下的数测试据层并没用什么区别,这里就不多介绍了,关于数据层的详细信息可见:developer.a测试手机是否被监控ndroid.com/jetpmvvm指的是ack/gui…

总结

相比老版的架构指南,新版主要是增加了网域层并修改了界面层,其中网域层是可选的,各位各根据自己的项目测试智商需求使用测试抑郁程度的问卷
而界面层则从MVVM架构变成了MVI架构,强调了数据的单向数据流动状态的集中管理。相比MVVM架构,MVI架构主要有以下优点

  1. 强调数据单向流动,很容易对状态变化进行跟踪和回溯,在数据一致性,可测试性,可维element翻译护性上都有一定优势
  2. 强调对UI State的集中管理,只需要订阅一个ViewState便可获取页面的所有状态,相对 MVVM 减少了不少模板代码
  3. 添加状态只需要添加一个属性,降测试仪低了ViewModelVie通信地址是写什么地址w层的通信成本,将业务逻辑集中在ViewModel中,协程View层只需要订阅状态然后刷新通信工程专业即可

当然在软件开发中测试工程师没有最好的架构,只有最合适的架构,各位可根据情况选用适合项目的架构,实际上在我看来Google在指南中推荐使用MVI而不再是MVVM,很可能是为了统一AndroidCompose的架构。因为在Compose中并elements中文翻译没有双向数据绑定,只有单向数据流动,因此MVI是最适合Compose的架构。

当然如果你的项目中没测试有使用DataBinding,或许也可以开始尝试一下使用MVI,不使用DataBind通信技术ingMVVM架构切换为MVI成本不高,切换起来也比较简单,在易用性,数据一致性,可测试性,可维护性等方面都有一定elementary是什么意思优势,后通信达续也可以无测试你适合学心理学吗缝切换到Compose

更多

MVVM 进阶版:MVI 架构了解一下~
MVI 架构更佳实践:支持 LiveData 属性监听
MVI 架构封装:快速优Element雅地实现网络请求携程旅行app官方下载
Android应用架构指南

发表评论

提供最优质的资源集合

立即查看 了解详情