好啦,那废话不多说,我们开始。
以下内容不做特别说明均是原文翻译。
最后给出了我的实现。
我几乎可以 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 在发生改变的时候发送适当的信息给它的依赖者。”
可以用下面这个图做个总结:
模型应该代表着视图当前的状态,可以是加载、成功,或者一个失败的状态。然后视图需要根据当前的状态去渲染 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。
上图是我的项目结构,非常的一目了然吧(狗头)。
我画了个不太标准的示意图:
首先看一下我这里的 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移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:Android)
最后
一线互联网Android面试题含详解(初级到高级专题)
这些题目是今年群友去腾讯、百度、小米、乐视、美团、58、猎豹、360、新浪、搜狐等一线互联网公司面试被问到的题目。并且大多数都整理了答案,熟悉这些知识点会大大增加通过前两轮技术面试的几率
如果设置门槛,很多开发者朋友会因此错过这套高级架构资料,错过提升成为架构师的可能。这就失去了我们的初衷;让更多人都能通过高效高质量的学习,提升自己的技术和格局,升职加薪。
最后送给大家一句话,望共勉,永远不要放弃自己的梦想和追求;
《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!
发者朋友会因此错过这套高级架构资料,错过提升成为架构师的可能。这就失去了我们的初衷;让更多人都能通过高效高质量的学习,提升自己的技术和格局,升职加薪。
最后送给大家一句话,望共勉,永远不要放弃自己的梦想和追求;
《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!