内容简介:说到MVVM,大家都会想起前端的MVVM框架,相较于前端MVVM的火热,它在移动开发领域就不那么热门了。Google在2015年才推出DataBinding框架,起步较晚,而且2015年是MVP模式爆发的一年,2016年是各种热修复、插件化爆发的一年,它没赶上好时机。PS:DataBinding和MVVM二者并不相同。MVVM是一种架构模式,而DataBinding是Android中实现数据与UI绑定的框架,是构建MVVM架构的一个工具,作用类似于增强版的ButterKnife。
概述
说到MVVM,大家都会想起前端的MVVM框架,相较于前端MVVM的火热,它在移动开发领域就不那么热门了。Google在2015年才推出DataBinding框架,起步较晚,而且2015年是MVP模式爆发的一年,2016年是各种热修复、插件化爆发的一年,它没赶上好时机。
PS:DataBinding和MVVM二者并不相同。MVVM是一种架构模式,而DataBinding是Android中实现数据与UI绑定的框架,是构建MVVM架构的一个工具,作用类似于增强版的ButterKnife。
自16年接触DataBinding以来,苦于这方面的知识较少,但是Databinding在使用过程中又十分便捷,所以一直以来都在不停探索怎样才能构建出合适的MVVM架构程序,在经过几次的项目重构之后,终于在近期结合Kotlin语言探索出了更适合Android的MVVM架构。
github地址: https://github.com/ditclear/PaoNet 9
我们先来看看什么是MVVM,然后再一步一步来阐述整个的MVVM框架
MVC、MVP、MVVM
我们先大致了解下Android开发的创建模式
MVC
Model:实体模型、数据的获取、存储等等
View:Activity、fragment、view、adapter、xml等等
Controller:为View层处理数据,业务等等
从这个结构来看,Android本身还是符合MVC架构的。不过由于作为纯View的xml功能太弱,以及controller能提供给开发者的作用较小,还不如在Activity页面直接进行处理,但这么做却造成了代码大爆炸。一个页面逻辑复杂的页面动辄上千行,注释没写好的话还十分不好维护,而且难以进行单元测试,所以这更像是一个Model-View的架构,不适用于打造稳定的Android项目。
MVP
Model:实体模型、数据的获取、存储等等
View:Activity、fragment、view、adapter、xml等等
Presenter:负责完成View与Model间的交互和业务逻辑,以回调返回结果。
前面说,Activity充当了View和Controller的作用, 造成了代码爆炸。而MVP架构很好的处理了这个问题。其核心理念是通过一个抽象的View接口(不是真正的View层)将Presenter与真正的View层进行解耦。Persenter持有该View接口,对该接口进行操作,而不是直接操作View层。这样就可以把视图操作和业务逻辑解耦,从而让Activity成为真正的View层。
这也是现今比较流行的架构,可是弊端也是有的。如果业务复杂了,也可能导致P层太臃肿,而且V和P层有一定耦合度,如果UI有什么地方需要更改,那么P层不只改一个地方那么简单,还需要改View的接口及其实现,牵一发动全身,运用MVP的同行都对此怨声载道。
MVVM
Model:实体模型、数据的获取、存储等等
View:Activity、fragment、view、adapter、xml等等
ViewModel:负责完成View与Model间的交互和业务逻辑,基于DataBinding改变UI
MVVM的目标和思想与MVP类似,但它没有MVP那令人厌烦的各种回调,利用DataBinding就可以更新UI和状态,达到理想的效果。
数据驱动UI
在使用MVC或MVP开发时,我们如果要更新UI,首先需要找到这个view的引用,然后赋予值,才能进行更新。在MVVM中,这就不需要了。MVVM是通过数据驱动UI的,这些都是自动完成。数据的重要性在MVVM架构中得到提高,成为主导因素。在这种架构模式中,开发者重点关注的是怎样处理数据,保证数据的正确性。
关注点分离
常见的错误就是把所有代码都写在Activity或者Fragment中。任何跟UI和系统交互无关的事情都不应该放在这些类当中。尽可能让它们保持简单轻量可以避免很多生命周期方面的问题。MVVM架构模式下,数据和业务逻辑都处于ViewModel中,ViewModel只关心数据和业务,不需要直接和UI打交道,而Model只需要提供ViewModel的数据源,View则关心如何显示数据和处理与用户的交互。
通过以上简述和与MVC、MVP的对比,我们可以发现MVVM还是很有优势的,而如果再搭配Kotlin语言的话,可以说是如虎添翼了。
如何开始?
其实结构已经很清晰了,我们只需要做M-V-VM层各层应该做的事情,做到关注点分离。
M层的关注点是怎么提供数据给ViewModel
ViewModel层关注点是怎么处理数据(包括使用DataBinding绑定数据,已经控制loading、empty状态)
View层的关注点是显示数据,接收用户的操作,调用ViewModel中的方法
为了打造更适合Android的MVVM架构,使用到的技术有AOP、Dagger2、RxJava、Retrofit、Room和Kotlin,并遵循统一的命名规范和调用准则,保证开发时的一致性。
以下是我们现今的架构:
MVVM
创建文章详情界面
接下来我将展示一下M-V-VM三层之间如何协作,以文章详情页面为例
V—VM
UI由ArtcileDetailActivity.kt及article_detail_activity.xml组成。
要驱动UI,我们的数据模型需要持有几个元素:
- Article Id:文章详情的id,用于加载文章详情
- title:文章的标题
- content:文章的内容
- state:加载状态,用一个State类来封装
我们将创建一个ArticleDetailViewModel.kt来保存。
一个ViewModel为特定的UI组件提供数据,比如fragment 或者 activity,并负责和数据处理的业务逻辑部分通信,比如调用其它组件加载数据或者转发用户的修改。ViewModel并不知道View的存在,也不会受configuration change影响。
现在我们有了三个文件。
article_detail_activity.xml: 定义页面的UI
ArticleDetailViewModel.kt: 为UI准备数据的类
ArtcileDetailActivity.kt: 显示ViewModel中的数据与响应用户交互的控制器
下面开始实现(为了简单,只显示了主要部分):
<?xml version="1.0" encoding="utf-8"?> <layout > <data> <import type="android.view.View"/> <variable name="vm" type="io.ditclear.app.viewmodel.ArticleDetailViewModel"/> </data> <android.support.design.widget.CoordinatorLayout> <android.support.design.widget.AppBarLayout> <android.support.design.widget.CollapsingToolbarLayout> <android.support.v7.widget.Toolbar app:title="@{vm.title}"/> </android.support.design.widget.CollapsingToolbarLayout> </android.support.design.widget.AppBarLayout> <android.support.v4.widget.NestedScrollView> <LinearLayout> <ProgressBar android:visibility="@{vm.loading?View.VISIBLE:View.GONE}"/> <WebView android:id="@+id/web_view" app:markdown="@{vm.content}" android:visibility="@{vm.loading?View.GONE:View.VISIBLE}"/> </LinearLayout> </android.support.v4.widget.NestedScrollView> </android.support.design.widget.CoordinatorLayout> </layout>
/** * 页面描述:ArticleDetailViewModel * @param repo 数据源Model(MVVM 中的M),负责提供ViewModel中需要处理的数据 * Created by ditclear on 2017/11/17. */ class ArticleDetailViewModel(val repo: ArticleRepository) { //////////////////data////////////// lateinit var articleId:Int val loading=ObservableBoolean(false) val content = ObservableField<String>() val title = ObservableField<String>() //////////////////binding////////////// fun loadArticle():Single<Article> = repo.getArticleDetail(articleId) .async() .doOnSuccess { t: Article? -> t?.let { title.set(it.title) content.set(it.content) } } .doOnSubscribe { startLoad()} .doAfterTerminate { stopLoad() } fun startLoad()=loading.set(true) fun stopLoad()=loading.set(false) }
```kotlin
class ArticleDetailActivity : BaseActivity
override fun getLayoutId(): Int = R.layout.article_detail_activity @Inject lateinit var viewModel: ArticleDetailViewModel //init override fun initView() { val articleID: Int? = intent?.extras?.getInt(Constants.KEY_ARTICLE_ID) if (articleID == null) { toast("文章不存在", ToastType.WARNING) finish() } getComponent().inject(this) mBinding.vm = viewModel.apply { this.articleID = articleID } } //加载数据 override fun loadData() { viewModel.loadData().compose(bindToLifecycle()) .subscribe({ t: Article? -> {} }, { t: Throwable? -> toastFailure(t) })
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- 构建一个混合的费用跟踪应用程序
- 构建安全计划 提升应用程序安全能力
- 第三章-构建Markdown应用程序
- 构建大型 React 应用程序的最佳实践
- 构建大型 React 应用程序的最佳实践
- 构建Kubernetes有状态应用程序的不同方法
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Elements of Programming
Alexander A. Stepanov、Paul McJones / Addison-Wesley Professional / 2009-6-19 / USD 39.99
Elements of Programming provides a different understanding of programming than is presented elsewhere. Its major premise is that practical programming, like other areas of science and engineering, mus......一起来看看 《Elements of Programming》 这本书的介绍吧!