AndroidMVVM

概述

说到AndroidMVVM,相信大家都会想到Google2015年推出的DataBinding框架。然而两者的概念是不一样的,不能混为一谈。MVVM是一种架构模式,而DataBinding是一个实现数据和UI绑定的框架,是构建MVVM模式的一个工具。

之前看过很多关于AndroidMVVM的博客,但大多数提到的都是DataBinding的基本用法,很少有文章仔细讲解在Android中是如何通过DataBinding去构建MVVM的应用框架的。View、ViewModel、Model每一层的职责如何?它们之间联系怎样、分工如何、代码应该如何设计?这是我写这篇文章的初衷。

接下来,我们先来看看什么是MVVM,然后再一步一步来设计整个MVVM框架。

MVC、MVP、MVVM

首先,我们先大致了解下Android开发中常见的模式。

MVC

View:XML布局文件。

Model:实体模型(数据的获取、存储、数据状态变化)。

Controllor:对应于Activity,处理数据、业务和UI。

从上面这个结构来看,Android本身的设计还是符合MVC架构的,但是Android中纯粹作为View的XML视图功能太弱,我们大量处理View的逻辑只能写在Activity中,这样Activity就充当了View和Controller两个角色,直接导致Activity中的代码大爆炸。相信大多数Android开发者都遇到过一个Acitivty数以千行的代码情况吧!所以,更贴切的说法是,这个MVC结构最终其实只是一个Model-View(Activity:View&Controller)的结构。

MVP

View:对应于Activity和XML,负责View的绘制以及与用户的交互。

Model:依然是实体模型。

Presenter:负责完成View与Model间的交互和业务逻辑。

前面我们说,Activity充当了View和Controller两个角色,MVP就能很好地解决这个问题,其核心理念是通过一个抽象的View接口(不是真正的View层)将Presenter与真正的View层进行解耦。Persenter持有该View接口,对该接口进行操作,而不是直接操作View层。这样就可以把视图操作和业务逻辑解耦,从而让Activity成为真正的View层。

但MVP也存在一些弊端:

Presenter(以下简称P)层与View(以下简称V)层是通过接口进行交互的,接口粒度不好控制。粒度太小,就会存在大量接口的情况,使代码太过碎版化;粒度太大,解耦效果不好。同时对于UI的输入和数据的变化,需要手动调用V层或者P层相关的接口,相对来说缺乏自动性、监听性。如果数据的变化能自动响应到UI、UI的输入能自动更新到数据,那该多好!

MVP是以UI为驱动的模型,更新UI都需要保证能获取到控件的引用,同时更新UI的时候要考虑当前是否是UI线程,也要考虑Activity的生命周期(是否已经销毁等)。

MVP是以UI和事件为驱动的传统模型,数据都是被动地通过UI控件做展示,但是由于数据的时变性,我们更希望数据能转被动为主动,希望数据能更有活性,由数据来驱动UI。

V层与P层还是有一定的耦合度。一旦V层某个UI元素更改,那么对应的接口就必须得改,数据如何映射到UI上、事件监听接口这些都需要转变,牵一发而动全身。如果这一层也能解耦就更好了。

复杂的业务同时也可能会导致P层太大,代码臃肿的问题依然不能解决。

MVVM

View:对应于Activity和XML,负责View的绘制以及与用户交互。

Model:实体模型。

ViewModel:负责完成View与Model间的交互,负责业务逻辑。

MVVM的目标和思想与MVP类似,利用数据绑定(DataBinding)、依赖属性(DependencyProperty)、命令(Command)、路由事件(RoutedEvent)等新特性,打造了一个更加灵活高效的架构。

数据驱动

在常规的开发模式中,数据变化需要更新UI的时候,需要先获取UI控件的引用,然后再更新UI。获取用户的输入和操作也需要通过UI控件的引用。在MVVM中,这些都是通过数据驱动来自动完成的,数据变化后会自动更新UI,UI的改变也能自动反馈到数据层,数据成为主导因素。这样MVVM层在业务逻辑处理中只要关心数据,不需要直接和UI打交道,在业务处理过程中简单方便很多。

低耦合度

MVVM模式中,数据是独立于UI的。

数据和业务逻辑处于一个独立的ViewModel中,ViewModel只需要关注数据和业务逻辑,不需要和UI或者控件打交道。UI想怎么处理数据都由UI自己决定,ViewModel不涉及任何和UI相关的事,也不持有UI控件的引用。即便是控件改变了(比如:TextView换成EditText),ViewModel也几乎不需要更改任何代码。它非常完美的解耦了View层和ViewModel,解决了上面我们所说的MVP的痛点。

更新UI

在MVVM中,数据发生变化后,我们在工作线程直接修改(在数据是线程安全的情况下)ViewModel的数据即可,不用再考虑要切到主线程更新UI了,这些事情相关框架都帮我们做了。

团队协作

MVVM的分工是非常明显的,由于View和ViewModel之间是松散耦合的:一个是处理业务和数据、一个是专门的UI处理。所以,完全由两个人分工来做,一个做UI(XML和Activity)一个写ViewModel,效率更高。

可复用性

一个ViewModel可以复用到多个View中。同样的一份数据,可以提供给不同的UI去做展示。对于版本迭代中频繁的UI改动,更新或新增一套View即可。如果想在UI上做A/BTesting,那MVVM是你不二选择。

单元测试

有些同学一看到单元测试,可能脑袋都大。是啊,写成一团浆糊的代码怎么可能做单元测试?如果你们以代码太烂无法写单元测试而逃避,那可真是不好的消息了。这时候,你需要MVVM来拯救。

我们前面说过了,ViewModel层做的事是数据处理和业务逻辑,View层中关注的是UI,两者完全没有依赖。不管是UI的单元测试还是业务逻辑的单元测试,都是低耦合的。在MVVM中数据是直接绑定到UI控件上的(部分数据是可以直接反映出UI上的内容),那么我们就可以直接通过修改绑定的数据源来间接做一些AndroidUI上的测试。

通过上面的简述以及模式的对比,我们可以发现MVVM的优势还是非常明显的。虽然目前Android开发中可能真正在使用MVVM的很少,但是值得我们去做一些探讨和调研。

如何构建MVVM应用框架

如何分工

构建MVVM框架首先要具体了解各个模块的分工。接下来我们来讲解View、ViewModel、Model它们各自的职责所在。

View

View层做的就是和UI相关的工作,我们只在XML、Activity和Fragment写View层的代码,View层不做和业务相关的事,也就是我们在Activity不写业务逻辑和业务数据相关的代码,更新UI通过数据绑定实现,尽量在ViewModel里面做(更新绑定的数据源即可),Activity要做的事就是初始化一些控件(如控件的颜色,添加的分割线),View层可以提供更新UI的接口(但是我们更倾向所有的UI元素都是通过数据来驱动更改UI),View层可以处理事件(但是我们更希望UI事件通过Command来绑定)。简单地说:View层不做任何业务逻辑、不涉及操作数据、不处理数据,UI和数据严格的分开。

ViewModel

ViewModel层做的事情刚好和View层相反,ViewModel只做和业务逻辑和业务数据相关的事,不做任何和UI相关的事情,ViewModel层不会持有任何控件的引用,更不会在ViewModel中通过UI控件的引用去做更新UI的事情。ViewModel就是专注于业务的逻辑处理,做的事情也都只是对数据的操作(这些数据绑定在相应的控件上会自动去更改UI)。同时DataBinding框架已经支持双向绑定,让我们可以通过双向绑定获取View层反馈给ViewModel层的数据,并对这些数据上进行操作。关于对UI控件事件的处理,我们也希望能把这些事件处理绑定到控件上,并把这些事件的处理统一化,为此我们通过对一些常用的事件做了封装,把一个个事件封装成一个个Command,对于每个事件我们用一个去处理就行了,会把你可能需要的数据带给你,这使得我们在ViewModel层处理事件的时候只需要关心处理数据就行了,具体见MVVMLightToolkit使用指南的Command部分。再强调一遍:ViewModel不做和UI相关的事。

Model

Model层最大的特点是被赋予了数据获取的职责,与我们平常Model层只定义实体对象的行为截然不同。实例中,数据的获取、存储、数据状态变化都是Model层的任务。Model包括实体模型(Bean)、Retrofit的Service,获取网络数据接口,本地存储(增删改查)接口,数据变化监听等。Model提供数据获取接口供ViewModel调用,经数据转换和操作并最终映射绑定到View层某个UI元素的属性上。

如何协作

关于协作,我们先来看下面的一张图:

上图反映了MVVM框架中各个模块的联系和数据流的走向,我们从每个模块一一拆分来看。那么我们重点就是下面的三个协作。

ViewModel与View的协作。

ViewModel与Model的协作。

ViewModel与ViewModel的协作。

ViewModel与View的协作

图2中ViewModel和View是通过绑定的方式连接在一起的,绑定分成两种:一种是数据绑定,一种是命令绑定。数据的绑定DataBinding已经提供好了,简单地定义一些就能把数据和控件绑定在一起了(如TextView的text属性),但是DataBinding框架提供的不够全面,比如说如何让一个URL绑定到一个ImageView,让这个ImageView能自动去加载url指定的图片,如何把数据源和布局模板绑定到一个ListView,让ListView可以不需要去写Adapter和ViewHolder相关的东西?这些就需要我们做一些工作和简单的封装。MVVMLightToolkit已经帮我们做了一部分的工作,详情可以查看MVVMLightToolkit使用指南。关于事件绑定也是一样,MVVMLightToolkit做了简单的封装,对于每个事件我们用一个去处理就行了,会把可能需要的数据带给你,这样我们处理事件的时候也只关心处理数据就行了。

由图1中ViewModel的模块中我们可以看出ViewModel类下面一般包含下面5个部分:

Context(上下文)

Model(数据源JavaBean)

DataField(数据绑定)

Command(命令绑定)

ChildViewModel(子ViewModel)

我们先来看下示例代码,然后再一一讲解5个部分是干嘛用的:

//Activitycontext;//model(数据源JavaBean)privateNewsService.Newsnews;private.NewstopNews;//数据绑定,绑定到UI的字段(datafield)publicfinalimageUrl=new<>();publicfinalhtml=new<>();publicfinaltitle=new<>();//一个变量包含了所有关于ViewStyle相关的字段publicfinalViewStyleviewStyle=newViewStyle();//命令绑定(command)publicfinalonRefreshCommand=newReplyCommand<>(()->{

})publicfinalReplyCommandonLoadMoreCommand=newReplyCommand<>((itemCount)->{

});//ChildViewModelpublicfinalObservableListitemViewModel=newObservableArrayList<>();/***ViewStyle关于控件的一些属性和业务数据无关的Style可以做一个包裹,这样代码比较美观,

ViewModel页面也不会有太多太杂的字段。**/publicstaticclassViewStyle{

publicfinalObservableBooleanisRefreshing=newObservableBoolean(true);

publicfinalObservableBooleanprogressRefreshing=newObservableBoolean(true);

}

Context



  • AndroidMVVM
    绛旓細璇村埌AndroidMVVM,鐩镐俊澶у閮戒細鎯冲埌Google2015骞存帹鍑虹殑DataBinding妗嗘灦銆傜劧鑰屼袱鑰呯殑姒傚康鏄笉涓鏍风殑,涓嶈兘娣蜂负涓璋堛侻VVM鏄竴绉嶆灦鏋勬ā寮,鑰孌ataBinding鏄竴涓疄鐜版暟鎹拰UI缁戝畾鐨勬鏋,鏄瀯寤篗VVM妯″紡鐨勪竴涓伐鍏枫 涔嬪墠鐪嬭繃寰堝鍏充簬AndroidMVVM鐨勫崥瀹,浣嗗ぇ澶氭暟鎻愬埌鐨勯兘鏄疍ataBinding鐨勫熀鏈敤娉,寰堝皯鏈夋枃绔犱粩缁嗚瑙e湪Android涓槸...
  • 濡備綍鏋勫缓Android MVVM搴旂敤绋嬪簭
    绛旓細鍦∕VVM妯″紡涓璙iewModel鍜孷iew鏄敤缁戝畾鍏崇郴鏉ュ疄鐜扮殑锛屾墍浠ユ湁浜咲ataBinding 浣挎垜浠瀯寤Android MVVM 搴旂敤绋嬪簭鎴愪负鍙兘銆備箣鍓嶇湅浜嗗緢澶氬叧浜嶥ataBinding鐨勫崥瀹㈠拰鐩稿叧鐨勪竴浜汥emo锛屽ぇ澶氭暟灏辨槸寰xml甯冨眬鏂囦欢浼犲叆涓浜涙暟鎹紝鐒跺悗鎶婅繖浜涙暟鎹粦瀹氬埌鎺т欢涓( 濡俆extView binding:text=鈥淍{user.name} )锛屾帴鐫鍦ㄨ繖浜涙帶浠朵笂锛...
  • Android 涓 MVC銆丮VP 鍜 MVVM 瀵规瘮
    绛旓細MVC銆丮VP鍜MVVM鏄父瑙佺殑涓夌鏋舵瀯璁捐妯″紡锛屽綋鍓峂VP鍜孧VVM鐨勪娇鐢ㄧ浉瀵规瘮杈冨箍娉涳紝褰撶劧MVC涔熷苟娌℃湁杩囨椂涔嬭銆侻VC (Model-View-Controller, 妯″瀷-瑙嗗浘-鎺у埗鍣)锛屾爣鍑嗙殑MVC鏄繖涓牱瀛愮殑锛氱畝杩帮細缂虹偣锛歁VP (Model-View-Presenter) 鏄疢VC鐨勬紨鍖栫増鏈紝鍑犱釜涓昏閮ㄥ垎濡備笅锛氱畝杩帮細瑙i噴锛氫紭鐐癸細缂虹偣锛歁VVM 鏄 Model-V...
  • android mvvm 瑙掕壊鍒嗗埆鏈夊摢浜涙媴浠
    绛旓細MVVM鐨勭洰鏍囧拰鎬濇兂MVP绫讳技锛屽埄鐢ㄦ暟鎹粦瀹(Data Binding)銆佷緷璧栧睘鎬(Dependency Property)銆佸懡浠(Command)銆佽矾鐢变簨浠(Routed Event)绛夋柊鐗规э紝鎵撻犱簡涓涓洿鍔犵伒娲婚珮鏁堢殑鏋舵瀯銆傛暟鎹┍鍔ㄥ湪MVVM涓紝浠ュ墠寮鍙戞ā寮忎腑蹇呴』鍏堝鐞嗕笟鍔℃暟鎹紝鐒跺悗鏍规嵁鐨勬暟鎹彉鍖栵紝鍘昏幏鍙朥I鐨勫紩鐢ㄧ劧鍚庢洿鏂癠I锛岄氳繃涔熸槸閫氳繃UI鏉ヨ幏鍙栫敤鎴疯緭鍏ワ紝...
  • Android Architecture(涓枃瀹樻柟鏂囨。)鈥斺MVVM銆丏ataBinding銆丩ifecycl...
    绛旓細瀹樻柟鏂囨。鍦板潃锛 https://developer.android.google.cn/jetpack/docs/guide Android Architecture鎺ㄨ崘浣跨敤MVVM鏋舵瀯锛氬叾涓紝鏂囨。涓壒鍒彁鍒颁簡锛氱畝鍗曟潵璇达紝 骞朵笉鏄 璇碝VVM灏辨槸鏈濂界殑缁撴瀯锛岃屾槸濂界殑鏋舵瀯蹇呴』婊¤冻浠ヤ笅涓ょ偣锛氫釜浜虹悊瑙e彧鏄崲浜嗙璇存硶锛屽疄璐ㄤ笂鍜屼箣鍓嶇殑MVC銆丮VP鏋舵瀯涓鏍凤紝鏈缁堢洰鏍囪繕鏄负浜嗘弧瓒 绋嬪簭璁捐...
  • Android鐪熺殑鎺ㄨ崘鐢∕VI妯″紡?MVI鍜MVVM鏈変粈涔堝尯鍒?
    绛旓細鎴戜滑android鐨勫緢澶氭妧鏈紝鍦ㄥ墠绔棭灏辩敤鈥滅儌浜嗏濄傛垜浠煡閬揗VP鍜MVVM鐨勭埞閮芥槸MVC銆侻VI鐨勭埞涔熸槸MVC銆侻VC鐨凜ontroller鏄懡浠ゆ槸缂栫▼缁勪欢锛屼笉鑳界洿鎺ュ疄鐜板搷搴斿紡缂栫▼鎬濇兂銆傚搷搴斿紡缂栫▼鑼冨紡锛圧eactive programming锛夛細瀹夊崜瀹樻柟鐨刢ompose妗嗘灦銆佸井淇″皬绋嬪簭銆丗lutter銆丷eact銆侀缚钂橴I鐨勫紑鍙戞鏋讹紝閮芥槸浣跨敤鍝嶅簲寮忓紑鍙戞鏋躲傝繖閲...
  • MVVM妗嗘灦涓璌otlin Flow鐨勫疄璺
    绛旓細鍦 Google Android 鍥㈤槦瀹e竷浜 Jetpack 鐨勮鍥炬ā鍨嬩箣鍚庯紝MVVM 鏋舵瀯宸茬粡鎴愪负浜 Android 寮鍙戞渶娴佽鐨勬灦鏋勪箣涓銆傚涓嬪浘鎵绀猴細涓嶈繃鍦 Google 鐨勫墠鏈熷畼鏂规枃妗d腑锛屽叾 Repository 灞傛槸鐩存帴浣跨敤 LiveData 鐨勶紝鑰屼笖杩 Jetpack Room 涔熷 LiveData 杩涜浜嗘敮鎸侊紝鎺ュ彛鍙互鐩存帴杩斿洖 LiveData 鐨勬暟鎹傛墍浠ュ湪寰堥暱涓娈垫椂闂...
  • Android寮鍙戦兘闇瑕佷娇鐢ㄤ粈涔堣瑷?
    绛旓細View鎸囩殑鏄鍥撅紝鍦ㄥ墠绔搴旂殑鏄疍OM ViewModel瑙傚療Model鍜孷iew鐨勫彉鍖栨潵鍋氭洿鏂帮紝瀹炵幇浜嗘暟鎹殑鍙屽悜缁戝畾銆 鍓嶇MVVM妗嗘灦涓昏鍖呮嫭锛歛ngularJS銆乺eactJS銆乂ueJS Android寮鍙戜腑鍦ㄥ摢浜涘満鍚堜笅浼氶渶瑕佷娇鐢ˋIDL 涓ユ牸鏉ヨ锛岀嚎绋嬫槸鍏变韩璧勬簮鐨勶紝鎵浠ョ嚎绋嬩箣闂存槸涓嶅瓨鍦ㄩ氫俊鐨勶紝Android閲岄潰鐨凥andle鏄敤鏉ヨВ鍐冲紓姝ヨ皟鐢ㄧ殑锛岃繖...
  • Android 寮鍙戞湁鍝簺鏂版妧鏈嚭鐜
    绛旓細Android 寮鍙戝垎妯″潡寮鍙戯紝浣跨敤 Dagger 鏉ユ澗鑰﹀悎妯″潡銆傜壒鍒煎緱涓浣撶殑鏄紝Dagger 2 鐜板湪鐢 Google 浜茶嚜鎺ョ銆 Dagger ‡ A fast dependency injector for Android and Java銆MVVM锛氳繖鏄洜涓哄紑濮嬪畼鏂规敮鎸 DataBinding锛屾妸 MVVM 鐩存帴甯﹀埌 Android 涓傛暟鎹粦瀹氬湪 Windows WPF 鍜 Web 宸茬粡闈炲父甯歌锛屽畠...
  • Android model灞傝璁
    绛旓細鍦ㄥ紑鍙慳pp鐨勮繃绋嬩腑锛屼笉绠℃槸浣跨敤浜唌vp杩樻槸mvc鐢氳嚦mvvm妯″紡,model灞傜殑璁捐鍩烘湰閮芥槸涓鏍风殑锛宮odel灞傚彲浠ヨ绉颁负鏁版嵁灞傦紝瀹冪殑涓昏浠诲姟灏辨槸涓轰笂灞傛彁渚涘悇绉嶇殑鏁版嵁鏈嶅姟锛屼笂灞傚畬鍏ㄤ笉闇瑕佸叧蹇冭繖浜涙暟鎹槸鏉ヨ嚜缃戠粶锛岃繕鏄唴瀛橈紝杩樻槸鏈湴瀛樺偍銆傞偅鎴戜滑灏遍氳繃涓涓椂搴忓浘鏉ョ湅涓媘odel灞傜殑宸ヤ綔娴佺▼ 涓婇潰鐨勬椂搴忓浘鍙槸鍙嶆槧浜嗘暟鎹...
  • 扩展阅读:xboxone game pass ... a little to the left ... maitland ward muse ... milkshake游戏下载 ... playstore+app+install ... wishroom plus2下载 ... pool break lite ... gmod马桶人模组游戏 ... 节奏盒子bonfire模组 ...

    本站交流只代表网友个人观点,与本站立场无关
    欢迎反馈与建议,请联系电邮
    2024© 车视网