Android _ MVVM 设计模式的一种实现方式,最新BAT大厂面试者整理的Android面试题目

前言

首先表明,这篇博客 80% 的内容是翻译自 Christopher Elias 的文章 《Understanding MVVM pattern for Android in 2021》。作者的原文题目翻译过来是 《理解 2021 年适用于 Android 的 MVVM 模式》,怕被喷标题党(因为感觉这个题目略大),所以我不太敢直接用原文题目Orz

本着尊重原创的精神,我是征得原作者同意后才敢翻译的,喏↓↓↓↓↓↓↓↓

Android _ MVVM 设计模式的一种实现方式,最新BAT大厂面试者整理的Android面试题目_第1张图片

网上介绍 MVVM 的文章有很多,讲得也都很棒!既然网上已经有那么多介绍 MVVM 的文章了,为什么我还是想要翻译这篇呢?

这篇文章它最吸引我的地方在于,作者在数据的获取到将数据渲染到界面的过程中抽象出了一个 State 类,将获取数据后的所有可能结果都封装到这个 State 类中,有很好的高内聚低耦合性,并且结合 Jetpack 组件中的 ViewModel、LiveData 简直不要太好用!所以我想要将这篇文章翻译成中文,一来是希望通过笔记的形式加深自己的印象,二来呢也是希望能让更多人看到这一优秀的实现方式。

基于我的理解,实现了一个小 demo。需求很简单,打开 APP,模拟从网络获取数据(一个水果名 List),并渲染到界面上,如下图。这里给出我的实现。

Android _ MVVM 设计模式的一种实现方式,最新BAT大厂面试者整理的Android面试题目_第2张图片

这里同时贴出 Christopher Elias 的 实现。这是一个大的项目,其中包含了这种实现方式,如果只是想要理解这种设计方式,我觉得看我的实现应该就足够了。Chris 的代码对于不熟悉 Kotlin 的人(譬如我)可能有点难以理解,他用到很多 Kotlin 的高级特性,代码写的非常漂亮,读一读大佬的实现还是可以学到一些东西的。

好啦,那废话不多说,我们开始。

以下内容不做特别说明均是原文翻译。

最后给出了我的实现。


我几乎可以 100% 确定你一定听过 MVC、MVP、MVVM、MVI、MV…。为了能够理解 MVVM 我们需要了解一些基础知识(别担心,我会直接挑重点讲的)。

问题是什么?

当我们开发 Android 应用程序时,我们倾向于将所有逻辑放进 Activitys、Fragments、Views 等等。

所以到最后,我们的视图做的就不仅仅是渲染 UI 了。他们可以将数据保存到 SharedPreferences、数据库中,甚至可以发起网络请求,并在一个地方处理所有这些额外的任务。

软件设计模式

软件设计模式是在软件设计中,对于给定上下文的常见问题的通用、可重用的解决方案。 维基百科

以上是一个关于软件设计模式的非常简短的定义,如果你想更深入了解,网上有很多资源可供参考。

好的,我们已经知道了问题所在,并且我们也知道有方法可以去解决它。

MVVM

V 表示 View,它可以是一个 Activity、Fragment,现在它甚至可以是 Composables 了!ViewModel 表示 Jetpack 组件中的 ViewModel,它是一个可以不受界面配置变化影响而存在的类。

OK,然后让我们把它们组装在一起,我们的 View 去订阅 ViewModel,然后对 Model 的变化做出响应。最后,轮到了 M,M 表示 Model,它是 emmmm 我的 model 是…

等等,什么是 “Model”?网上有很多文章告诉你说 Model 是你获取数据的“地方”,是你的仓库(repository)的所在地,等等。我认为这是错的,我将告诉你为什么。

Model 其实并不是什么新的概念,它最初是由 Trygve Reenskaug 于1979年定义的,作为 MVC 体系结构的一部分。

“Model 对表示状态、结构和用户心理模型负责。”

“View 负责展示它从一个或者多个 Model 获取的数据。”

“使 View 依赖于 Model,并且 Model 在发生改变的时候发送适当的信息给它的依赖者。”

可以用下面这个图做个总结:

![image.png](https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/48a1e82b

《Android学习笔记总结+最新移动架构视频+大厂安卓面试真题+项目实战源码讲义》

【docs.qq.com/doc/DSkNLaERkbnFoS0ZF】 完整内容开源分享

1cdf4f96bd53195000efc9e6~tplv-k3u1fbpfcp-watermark.image)

模型应该代表着视图当前的状态,可以是加载、成功,或者一个失败的状态。然后视图需要根据当前的状态去渲染 UI。

代码

假设我们需要在应用中展示一个电影列表。我们可以用下面这个类来表示状态:

/**

  • Represents the state to render the UI in MovieListFragment.
  • @param isLoading if true we have to show a progress bar, else hide the progress bar.
  • @param movies this list will be submited into recyclerview adapter.
  • @param error OneTimeEvent that wraps a failure object for display a Toast, Snackbar, etc only once.
    */
    data class MovieListUiState(
    val isLoading: Boolean = false,
    val movies: List = emptyList(),
    val error: OneTimeEvent? = null
    )

啥是 OneTimeEvent?它只是一个普通的功能类,可以使我们只消耗一个对象一次,这样就可以避免当用户回到屏幕时显示 snackbars、toast 两次。

啥是 Failure?它其实是一个密封类(Sealed Class),可以表示任何类型的错误,你可以使用 Exception、String 等类型的错误表示,只要是可以清楚地告诉你的代码出了什么问题就行。

接下来的问题是,我们如何优雅地渲染界面?

class MovieListFragment : Fragment(R.layout.fragment_movie_list) {

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
initView()
collectUiState()
}

private fun initView() {
binding.rvMovies.adapter = MovieListAdapter()
}

private fun collectUiState() {
viewLifecycleOwner.lifecycleScope.launch {
moviesViewModel.uiState.collect { state ->
renderUiState(state)
}
}
}

private fun renderUiState(state: MovieListUiState) {
with(state) {
// Progress
binding.progressBarMovies.isVisible = isLoading

// Bind movies.
(binding.rvMovies.adapter as MovieListAdapter)
.submitList(movies)

// Empty view
binding.tvMoviesEmpty.isVisible = !isLoading && movies.isEmpty()

// Display error if any. Only once.
error?.let {
it.consumeOnce { failure ->
Toast.makeText(
requireContext(),
“$failure”,
Toast.LENGTH_LONG
).show()
}
}
}
}


}

这里解释一下上面代码中的 3 个方法。

  • initView() 只负责初始化 RecyclerView 的 Adapter。

  • collectUiState() 获取 UI 状态 Flow。除了 Flow 以外,也可以使用 LiveData,这不重要。

  • renderUiState(state: MovieListUiState) 负责根据当前状态渲染界面。

最后,那 ViewModel 呢?ViewModel 是准备数据的(数据可以来自于你的 Repository 等),并且使用返回的结果去修改状态。

好了,以上就是全部啦!现在你应该知道了在你的 MVVM 架构中究竟啥是 Model。

接下来的几天我将上传更多的内容,以帮助您在 2021 年开发出很优秀的 Android 应用。这是一个我的 Playground 项目,并且我将在接下来的博客中写到其中所用到的知识。


我的实现

好啦,以上就是原作者的原文翻译。原作者的实现非常漂亮简洁,其中的 OneTimeEvent 是我第一次了解到,我觉得这是一个非常好的值得借鉴的地方,以后可以用在自己的项目中。

接下来,我将贴出基于我的理解实现的 demo。

Android _ MVVM 设计模式的一种实现方式,最新BAT大厂面试者整理的Android面试题目_第3张图片

上图是我的项目结构,非常的一目了然吧(狗头)。

我画了个不太标准的示意图:

Android _ MVVM 设计模式的一种实现方式,最新BAT大厂面试者整理的Android面试题目_第4张图片

首先看一下我这里的 State :

data class MainActivityUIState (
val isLoading: Boolean = false,
val fruits: List = emptyList(),
val error: String? = null
)

跟 Chris 实现一样,只是这里简单的使用一个 String 来表示错误信息。

接下来是我的 Model 部分的实现:

class FruitRepository {

fun getFruitsFromRemote(onGetFruitsListener: OnGetFruitsListener) {

val error: String? = null
)

跟 Chris 实现一样,只是这里简单的使用一个 String 来表示错误信息。

接下来是我的 Model 部分的实现:

class FruitRepository {

fun getFruitsFromRemote(onGetFruitsListener: OnGetFruitsListener) {

你可能感兴趣的:(程序员,面试,android,移动开发)