Android _ MVVM 设计模式的一种实现方式(1)

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

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

最后给出了我的实现。


我几乎可以 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

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

image.png

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

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

非依赖倒置.png

首先看一下我这里的 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) {

Thread.sleep(1500)

onGetFruitsListener.onSuccess(generateFruits())
}

private fun generateFruits(): List {
val fruits: MutableList = ArrayList()

fruits.apply {
add(Fruit(“apple”))
add(Fruit(“orange”))
add(Fruit(“watermelon”))
add(Fruit(“banana”))
add(Fruit(“peach”))
add(Fruit(“pineapple”))
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则近万的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

img

img

img

img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:Android)

最后

一线互联网Android面试题含详解(初级到高级专题)

这些题目是今年群友去腾讯、百度、小米、乐视、美团、58、猎豹、360、新浪、搜狐等一线互联网公司面试被问到的题目。并且大多数都整理了答案,熟悉这些知识点会大大增加通过前两轮技术面试的几率

如果设置门槛,很多开发者朋友会因此错过这套高级架构资料,错过提升成为架构师的可能。这就失去了我们的初衷;让更多人都能通过高效高质量的学习,提升自己的技术和格局,升职加薪。

最后送给大家一句话,望共勉,永远不要放弃自己的梦想和追求;

《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!

发者朋友会因此错过这套高级架构资料,错过提升成为架构师的可能。这就失去了我们的初衷;让更多人都能通过高效高质量的学习,提升自己的技术和格局,升职加薪。

最后送给大家一句话,望共勉,永远不要放弃自己的梦想和追求;

《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值