MVVM 模式介绍--摘自网友文章160402

原文地址:https://mp.weixin.qq.com/s?__biz=MzA3MjA4NjE3NQ==&mid=404502568&idx=1&sn=fe512f9820b99d3cc8212e363ff57195&scene=1&srcid=0407PIdwHgMcWOBI7P2zEgCa&key=b28b03434249256bd8382e5caf525bcb36d6b31e18f2e933d895b3f91b6a6e10a1d42d613b275625f39a121137975d80&ascene=0&uin=Mjc3OTU3Nzk1&devicetype=iMac+MacBookPro10%2C1+OSX+OSX+10.10.5+build%2814F27%29&version=11020201&pass_ticket=%2F8olw2Mg3%2BO3Hdredp8Koo4%2FdLP647sSn5SKAT3uD06Nfhyo6Peebt0qCKuYnh6O

什么是 MVVM 模式?

 

Model-View-ViewModel 就是将其中的 View 的状态和行为抽象化,让我们可以将 UI 和业务逻辑分开。当然这些工作 ViewModel 已经帮我们做了,它可以取出 Model 的数据同时帮忙处理 View 中由于需要展示内容而涉及的业务逻辑。


MVVM模式是通过以下三个核心组件组成,每个都有它自己独特的角色:


  • Model-包含了业务和验证逻辑的数据模型

  • View-定义屏幕中 View 的结构,布局和外观

  • ViewModel-扮演「View」和「Model」之间的使者,帮忙处理 View 的全部业务逻辑


18094912_d2ox.jpg


那这和我们曾经用过的 MVC 模式有什么不同呢?以下是 MVC 的结构


  • ViewController 的顶端,而 ModelController 的底部

  • Controller 需要同时关注 ViewModel

  • View 只能知道 Model 的存在并且能在 Model 的值变更时收到通知


MVVM 模式和 MVC 有些类似,但有以下不同:


  • ViewModel 替换了 Controller,在 UI 层之下

  • ViewModelView 暴露它所需要的数据和指令对象

  • ViewModel 接收来自 Model 的数据


你可以看到这两种模式有着相似的结构,但新加入的 ViewModel 是用不同的方法将组件们联系起来的,它是双向的,而 MVC 只能单向连接。


概括起来,MVVM 是由 MVC 发展而来-通过在 Model 之上而在 View 之下增加一个非视觉的组件将来自 Model 的数据映射到 View 中。接下来,我们将更多地看到 MVVM 的这种特性。


THE HACKER NEWS READER


正如前面提及过的,我将我原来的一个项目拆开为这篇文章服务。这款应用有以下几种特性:


  • 查看帖子列表

  • 查看单个帖子

  • 查看帖子下的评论

  • 查看指定作者的帖子


下面的图片能让你很快了解它是怎么工作的:


18094912_MDpU.jpg


左边的图片展示的是帖子的列表,它也是这款应用的主要部分,接下来右边的图片展示的是该帖子的评论列表,它和前者有相似的地方,但也有一些不同,我们将在后面看到。


展示帖子




每个帖子信息都用 RecyclerView 所包含的 CardView 包装起来,正如上图展示的。


使用 MVVM 我们可以将不同层抽象出来很好的实现这些卡片,这意味着每个 MVVM 组件只要处理它被分配的任务即可。通过使用前面介绍的 MVVM 的不同组件,组合在一起后能构造出我们的帖子卡片实例,那么我们该如何将它们从布局中抽离出来?




MODEL

简单来说,Model 由那些帖子的业务逻辑组成,包括一些像 id,name,text 之类的属性,以下代码展示了该类的部分代码:





为了可读性,上面的 POST 类中去掉了一些 Parcelable 变量和方法


这里你可以看到 Post 类只包含所有它的属性,没有一点别的逻辑 - 别的组件会处理它们。


View


View 的任务是定义布局,外观和结构。View 最好能完全通过 XML 来定义,即使它包含些许 Java 代码也不应该有业务逻辑部分,


View 会通过绑定从 ViewModel 中取出数据。在运行时,若 ViewModel 的属性的值有变化的话它会通知 View 来更新UI。


首先,我们先给 RecyclerView 传入一个自定义的适配器。为此,我们需要让我们的 BindingHolder 类持有对 Binding 的引用。




onBindViewHolder() 方法才是真正将 ViewModelView 绑定的地方。我们获取一个 ItemPostBinding 对象(它会被 item_post 布局自动生成),然后将新建的 PostViewModel 对象传给它的 ViewModel 引用。




下面就是完整的 PostAdaper 类:





看下我们的XML布局,首先我们要将所有的布局都包含在layout标签下,同时使用data标签来声明我们的 ViewModel:




声明 ViewModel 可以让我们在整个布局中引用它,在 item_post 布局中我们会多次用到 ViewModel


androidText-你可以从 ViewModel 中引用相应的方法给文本视图设置内容。正如下面你所看到的 @{viewModel.postTitle},它从 ViewModel 中引用了 getPostTitle() 方法-它将返回相应帖子的标题。


onClick-我们也可以引用单击事件到布局文件中。如你所看到的,@{viewModel.onClickPost} 是指从 ViewModel 中引用 onClickPost() 方法-它将返回一个能处理单击事件的 OnClickListener 对象。


visibility - 控制去 comments activity 的入口,依赖于该帖子是否有相应的评论。通过检查 comments list 的长度来决定该 visibility 的值,这些操作都是在 ViewModel 中完成的。在这里,我们引用了它的 getCommentsVisiblity() 方法来计算是否该显示








这样做实在太棒了,我们能抽象出显示逻辑到我们的布局文件中,让我们的 ViewModel 来关注它们。


VIEWMODEL


ViewModel 扮演了 ViewModel 之间使者的角色,让它来关注所有涉及到 View 的业务逻辑,同时它可以访问 Model 的方法和属性,这些最终会作用到 View 中。通过 ViewModel,可以移除原本需要在别的组件中返回或处理的数据。


在这里,PostViewModelPost 对象来处理 CardView 需要显示的内容,在下面的类中,你可以看到一系列的方法,每个方法对最终作用于我们的帖子视图。


getPostTitle()-通过 Post 对象返回一个帖子的标题


getPostAuthor()-这个方法首先会从应用的resources中获取相应的字符串,然后传入Post对象的author属性对它进行格式化,如果isUserPosts 等于true我们就需要加入下划线,最终返回该字符串。


getCommentsVisibility()-该方法决定是否显示有关评论的TextView onClickPost()-该方法返回相应View需要的OnClickListener


这些例子表明不同的业务逻辑都有我们的 ViewModel 来处理。下面就是我们 PostViewModel 类的完整代码以及那些被item_post布局引用的方法。






是不是很爽?正如你看到的,我们的 PostViewModel 关注以下方面: 


  • 维护 Post 对象的属性,最终会在 View 中展示

  • 对这些属性进行相应的格式化

  • 通过 onclick 属性给相应的views对提供点击事件的支持

  • 通过 Post 对象的属性处理相关 views 的显示


测试 VIEWMODEL


使用 MVVM 的一大好处是我们可以很容易对 ViewModel 进行单元测试。在 PostViewModel 中,可以写些简单的测试方法来验证我们的 ViewModel 是否正确实现。


shouldGetPostScore()-测试getPostScore()方法,确认该帖子的得分是否正确地格式化成字符串对象并返回。


shouldGetPostTitle()-测试getPostTitle()方法,确认该帖子的标题被正确返回。


shouldGetPostAuthor()-测试getPostAuthor()方法,确认返回的帖子的作者被正确地格式化了


shouldGetCommentsVisiblity()-测试getCommentsVisibility()方法是否正确返回了visibility属性的值,它将会用在帖子的 Comments 按钮中。我们传入一个包含不同状态的ArrayLists来确认它是否能正确返回。





现在我们可以知道的 ViewModel 已经正确工作了!!


评论


实现评论的方法和前面很像但还是有点不同。


有两个不同的 ViewModel 被用来操作这次评论, CommentHeaderViewModelCommentViewModel。正如你在CommentAdapter中看到的,我们的 View 有两种的不同类型:


private static final int VIEW_TYPE_COMMENT = 0;

private static final int VIEW_TYPE_HEADER = 1;


如果该帖子是一个发问的帖子,我们将在屏幕的顶端显示一个头部,它显示所问的问题-接着评论会正常显示在下面。同时你应该会注意到在 onCreateViewHolder() 中我们会通过判断 VIEW_TYPE 来加载不同的布局,它会返回两种不同布局中的其中一种。




接着在我们的 onBindViewHolder() 方法中我们会根据不同的视图类型来创建绑定。这是因为不同的 ViewModel 对头部有不同的处理方法




这就是它们的不同点,评论部分有两个不同的 ViewModel 类型 — 取决于该帖子是否是发问类的帖子。


总结


如果正确使用,数据绑定类库可能会改变我们开发应用的方式。当然,还有其他方法实现数据的绑定,使用 MVVM 模式只是其中的一种途径。


比如,你可以在布局中引用我们的 Model 然后通过它的变量引用直接访问它的属性:




同时我们可以很容易从adapers和classes中移除一些基础的显示逻辑。下面有种很新颖的方法实现我们这种需求:


18094912_IpsC.jpg


18094912_PsDu.jpg


这就是我看到上面实现方式的表情!


我认为这是数据绑定类库中不好的地方,它将 View 的显示逻辑包含到了 View 中。不仅会造成混乱,也让我们的测试和调试变的更加困难,因为它将逻辑和布局混淆在一起。


当然,认定MVVM是开发应用的正确方式还为时过早,但这次尝试也让我有机会见识到未来项目的一种趋势。如果你想阅读更多有关数据绑定类库的文章,你可以看这里。同时微软也有一篇关于MVVM通俗易懂的文章


我很愿意听取你们想法,如果你们有任何的看法和建议可以随时发 Tweet 和我讨论!


转载于:https://my.oschina.net/u/2531415/blog/661596

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值