初探安卓MVVM框架設計

初探安卓MVVM框架設計#

一. 什么是MVVM?

MVVM是近幾年流行的一種設計框架,基于該框架設計的應用程序具有良好的解耦和可擴展性,大幅降低了維護成本,提高了程序員的開發(fā)效率.在了解MVVM框架之前,我們有必要回顧一下其他設計框架.

1. MVC模式

MVC模式的意思是,軟件可以分成三個部分.

視圖(View):用戶界面

控制器(Controller):業(yè)務邏輯

模型(Model):數(shù)據(jù)保存

各部分之間的通信方式如下.


1.View傳送指令到Controller

2.Controller完成業(yè)務邏輯后,要求Model改變狀態(tài)

3.Model將新的數(shù)據(jù)發(fā)送到View,用戶得到反饋

所有通信都是單向的.我們傳統(tǒng)的Android開發(fā)都是基于這種模式.每一層可以代表我們常用的如下組件:

Model層: sqlite數(shù)據(jù)庫, JavaBean, SharedPreference, sdcard,獲取網(wǎng)絡數(shù)據(jù)的api等
View層: xml布局文件,自定義控件等

Controller層: Activity等
此處需要注意的是,在傳統(tǒng)的MVC設計模式中,

Activity屬于Controller層而不是View層,因為Activity即承擔了數(shù)據(jù)調用,也承擔了界面展示,相當于View和Model中間的協(xié)調器.很多初學者都會誤認為Activity屬于View層.當然,這種說法僅限用MVC模式,換做其他模式就不一定了哦!

2. MVP模式

MVC模式普及了一段時間之后,逐漸暴露出一些問題.比如我們發(fā)現(xiàn),
Activity中寫的代碼太多,有時候一個Activity甚至達到了四五千行代碼,維護起來極為不便.原因也很明顯,就是Activity既參與api訪問和數(shù)據(jù)調用,又參與了界面的更新,職能劃分不明確,沒有完全實現(xiàn)解耦.我們的想法是,能不能讓Activity只做界面響應和更新,其他業(yè)務邏輯全部由另外一個單獨模塊來完成?于是MVP誕生了.

MVP模式將Controller改名為Presenter,同時改變了通信方向.

1.各部分之間的通信,都是雙向的.

2.View與Model不發(fā)生聯(lián)系,都通過Presenter傳遞.

3.View非常薄,不部署任何業(yè)務邏輯,稱為"被動視圖"(Passive View),即沒有任何主動性,而Presenter非常厚,所有邏輯都部署在那里.

當這樣調整了之后, Activity就純粹屬于View層了,所有業(yè)務邏輯全由Presenter來完成.當View界面被用戶操作時(比如按鈕點擊), View層就會調用Presenter完成相關業(yè)務邏輯,而Presenter完成了之后,就會將結果以回調的形式傳遞給View層,由View層完成界面刷新.具體代碼如何實現(xiàn)我就不多說了,因為我們今天的重點是MVVM,如果有興趣研究的話可以在網(wǎng)上搜索MVP相關的例子程序,我也找了一個,僅供參考:
http://blog.csdn.net/vector_yi/article/details/24719873

3. MVVM模式

當我們采用MVP模式之后,發(fā)現(xiàn)Activity幾乎沒啥事可做了,我們的項目代碼層級也清晰了,也好維護了.但是MVP也有缺點,比如,為了實現(xiàn)MVP,我們需要額外增加好多接口和類,比如,一個Activity需要對應一個Presenter類和Presenter接口,同時為了方便Activity和Presenter進行通信,還得再定義一個回調接口IView,也就是說,每一個Activity都需要額外增加兩個接口和一個類,無疑提高了代碼量.而MVVM的誕生,就解決了這個問題!

MVVM模式將Presenter改名為ViewModel,基本上與MVP模式完全一致.


唯一的區(qū)別是,它采用雙向綁定(data-binding):View的變動,自動反映在ViewModel,反之亦然.

有沒有注意到, MVVM和MVP幾乎是一樣的,唯一的不同就在于View和ViewModel之間的那根線, MVP是兩根,表示View調用Presenter執(zhí)行邏輯,Presenter調用View來返回數(shù)據(jù),更新界面;MVVM中只有一根線兩個箭頭,代表的是View和ViewModel雙向綁定,自動同步數(shù)據(jù),無需手動調用相關方法進行通信,從而減少了代碼量.而這種雙向綁定的機制,都歸功于谷歌推出的DataBinding的新功能.下面我們來研究一下到底什么是DataBinding.

二. 使用DataBinding構建MVVM框架

2.1 什么是DataBinding

2015 Google IO大會帶來的DataBinding庫使得Android開發(fā)者可以方便的實現(xiàn)MVVM架構模式.使用DataBinding可以改善應用程序的開發(fā),使代碼更加干凈優(yōu)雅.

DataBinding的使用教程在網(wǎng)上已經(jīng)很多了,我在這里只是簡單提一下最基本的用法,大家體驗一下就好.如果想更深入學習的話,建議查看谷歌官方文檔:https://developer.android.com/topic/libraries/data-binding/index.html

2.2 DataBinding環(huán)境配置

1.由于新版Android Studio已經(jīng)內置了DataBinding的功能,為了方便開發(fā),請確保使用AndroidStudio 1.3及以上的版本.

2.在app的build.gradle文件中添加下面的內容:

android {
....
dataBinding {
enabled =true
}
}

3.重新編譯項目,配置完成.

2.3 DataBinding的基本使用

1.布局文件

根標簽使用layout,在layout標簽下用data標簽來配置數(shù)據(jù),例子如下:

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
    <data>
        <variable name="user" type="cn.itcast.mvvmdemo.User"/>
    </data>
    <LinearLayout
        android:orientation="vertical"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
        <TextView android:layout_width="wrap_content"
                  android:layout_height="wrap_content"
                  android:text="@{user.firstname}"/>
        <TextView android:layout_width="wrap_content"
                  android:layout_height="wrap_content"
                  android:text="@{user.lastname}"/>
    </LinearLayout>
</layout>

<variable name="user" type="cn.itcast.mvvmdemo.User"/>

這句話代表,聲明了一個user變量,類型是cn.itcast.mvvmdemo.User,當然這個User要提前定義.

public class User {
private String firstname;
private String lastname;
public User(String firstname, Stringlastname) {
this.firstname = firstname;
this.lastname = lastname;
}
public String getFirstname() {
return firstname;
}
public void setFirstname(Stringfirstname) {
this.firstname = firstname;
}
public String getLastname() {
return lastname;
}
public void setLastname(Stringlastname) {
this.lastname = lastname;
}
}
<TextView android:layout_width="wrap_content"
                  android:layout_height="wrap_content"
                  android:text="@{user.firstname}"/>

控件布局寫法和以前一樣,唯一不同之處在于控件內容的賦值部分.以前我們都會寫一個默認值,然后再在代碼中動態(tài)修改控件的值.此時已經(jīng)不需要了. @{user.firstname}代表當前TextView的值取自于user對象中的firstname字段.

2. Activity代碼

public class MainActivity extends AppCompatActivity {
private User user;
@Override
protected void onCreate(BundlesavedInstanceState) {
super.onCreate(savedInstanceState);
ActivityMainBinding binding =DataBindingUtil.setContentView(this, R.layout.activity_main);
user = new User("尼古拉斯凱奇", "趙四");
binding.setUser(user);
}
}

ActivityMainBinding是DataBinding自動根據(jù)布局文件生成的類,不需要手動創(chuàng)建.該類的命名方式取自于布局文件的名稱.比如布局文件名叫activity_main,那么生成的類名就叫ActivityMainBinding.

當使用DataBinding時,需要用DataBindingUtil來設置Activity的布局.
binding.setUser(user);表示將user對象和布局文件綁定在了一起,
user對象的所有屬性值都可以同步映射到布局文件的控件中.

3. 運行效果

你會發(fā)現(xiàn),我們沒有像往常那樣在activity中findViewById,找到控件后給動態(tài)賦值,而是通過DataBinding的方式直接將對象的值作用在了布局文件中,從而使我們的代碼更加優(yōu)雅和簡潔.

2.3 DataBinding響應點擊事件

1.首先,寫一個事件處理器MyHandler

public class MyHandler {
public void onButtonClick(View view){
System.out.println("按鈕被點擊了");
}
}

這是一個普通的類,在onButtonClick中處理按鈕點擊后應該執(zhí)行的操作.

2.在之前布局文件的基礎上,添加一個按鈕

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">

    <data>

        <variable
            name="user"
            type="cn.itcast.mvvmdemo.User"/>

        <variable
            name="handler"
            type="cn.itcast.mvvmdemo.MyHandler"/>
    </data>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{user.firstname}"/>

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{user.lastname}"/>

        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:onClick="@{handler.onButtonClick}"
            android:text="點擊我"
            />
    </LinearLayout>
</layout>

在data中聲明handler,類型是MyHandler,在Button的onClick中定義要執(zhí)行的操作.
android:onClick="@{handler.onButtonClick}"

3.在Activity中,將MyHandler設置給Binding對象.

binding.setHandler(new MyHandler());

4.運行后看效果

2.4 數(shù)據(jù)變化后同步更新界面

點擊按鈕之后,我們想修改一下firstname和lastname的值,然后更新界面.如果采用DataBinding的話,我們會怎么做?

1.將用戶對象傳遞給MyHandler

public class MyHandler {
private User user;
public MyHandler(User user) {
this.user = user;
}
public void onButtonClick(View view){
System.out.println("按鈕被點擊了");
user.setFirstname("蒙拉麗莎");
user.setLastname("鴨蛋");
}
}

在按鈕點擊的時候,修改了user的firstname和lastname.如果放在往常,你肯定就立馬想找到那兩個TextView對象來重新設置數(shù)據(jù),而現(xiàn)在,你什么都不用做,只要數(shù)據(jù)變了,界面就會立即同步更新.有這么神奇?其實你得提前做好準備,才會有這樣的效果.

2.我們需要把User類調整一下:

public class User extends BaseObservable {
private String firstname;
private String lastname;
public User(String firstname, Stringlastname) {
this.firstname = firstname;
this.lastname = lastname;
}
@Bindable
public String getFirstname() {
return firstname;
}
public void setFirstname(String firstname) {
this.firstname = firstname;
notifyPropertyChanged(BR.firstname);
}
@Bindable
public String getLastname() {
return lastname;
}
public void setLastname(String lastname){
this.lastname = lastname;
notifyPropertyChanged(BR.lastname);
}
}

在getFirstname和getLastname兩個方法中加注解@Bindable,這樣的話DataBinding會自動在BR文件中生成這兩個字段的id. BR文件類似于R文件,是DataBinding特有的用于維護id的一個文件. BR文件由編譯器自動生成.

在setFirstname和setLastname的方法中添加notifyPropertyChanged方法,同時將你要更新的字段id傳遞過去.此方法用于通知系統(tǒng)數(shù)據(jù)已經(jīng)變化,需要更新界面.

3.我們案例的最終項目結構如下圖所示:

三. 總結

在學習MVVM框架時我一直有一個糾結:MVC和MVP結構很清晰,我很容易能分清楚哪個組件屬于哪個模塊,但到了MVVM我就有點暈了,因為網(wǎng)上所有介紹MVVM的文章幾乎都指向了DataBinding,并沒有講到具體每一層對應哪些組件.目前就我的初步了解,我大概會這么劃分:

View層: xml, Activity,自定義控件等;
Model層: sqlite數(shù)據(jù)庫, JavaBean,SharedPreference, sdcard,獲取網(wǎng)絡數(shù)據(jù)的api等
ViewModel層:獨立的業(yè)務邏輯處理模塊,部分參與業(yè)務邏輯的JavaBean

在我們的例子項目中,MainActivity, activity_main.xml屬于View層; User屬于Model層; MyHandler屬于ViewModle層.

不過后來我又想了一下,我們真有必要劃分清楚誰是View,誰是ViewModel,誰是Model嗎?程序設計本來就很復雜,難免會碰到一些模棱兩可的模塊,各個層都參與一下,但又不屬于任何一層.我們開發(fā)應用程序是為了實現(xiàn)功能,我們進行框架設計是為了提高擴展性并降低維護成本,在這種大前提下,我們的細節(jié)如何處理就已經(jīng)無關緊要了.事實上,當你采用了DataBinding來構建你的程序時,你其實就已經(jīng)在用MVVM框架了.

當然DataBinding的用法還有很多,此文介紹的只是冰山一角,比如如何在ListView和RecyclerView中使用DataBinding,布局文件中關于DataBinding的高級用法等等,此文都沒有提及.如果你想了解更多,就請關注官方文檔.

關于MVVM和DataBinding的資料和博客,網(wǎng)上已經(jīng)有很多了,由于MVVM內容確實繁雜,所以網(wǎng)上的文章沒有特別全面的,側重點都有所不同.當然,此文是從另一個角度來重新解讀了一下MVVM模式,如果能從此文中獲取對你有益的內容,會讓我倍感欣慰.

Demo附件下載鏈接: http://pan.baidu.com/s/1pLligyf

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市愈捅,隨后出現(xiàn)的幾起案子遏考,更是在濱河造成了極大的恐慌,老刑警劉巖蓝谨,帶你破解...
    沈念sama閱讀 211,265評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件灌具,死亡現(xiàn)場離奇詭異,居然都是意外死亡譬巫,警方通過查閱死者的電腦和手機咖楣,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,078評論 2 385
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來芦昔,“玉大人截歉,你說我怎么就攤上這事⊙塘悖” “怎么了瘪松?”我有些...
    開封第一講書人閱讀 156,852評論 0 347
  • 文/不壞的土叔 我叫張陵,是天一觀的道長锨阿。 經(jīng)常有香客問我宵睦,道長,這世上最難降的妖魔是什么墅诡? 我笑而不...
    開封第一講書人閱讀 56,408評論 1 283
  • 正文 為了忘掉前任壳嚎,我火速辦了婚禮,結果婚禮上末早,老公的妹妹穿的比我還像新娘烟馅。我一直安慰自己,他們只是感情好然磷,可當我...
    茶點故事閱讀 65,445評論 5 384
  • 文/花漫 我一把揭開白布郑趁。 她就那樣靜靜地躺著,像睡著了一般姿搜。 火紅的嫁衣襯著肌膚如雪寡润。 梳的紋絲不亂的頭發(fā)上捆憎,一...
    開封第一講書人閱讀 49,772評論 1 290
  • 那天,我揣著相機與錄音梭纹,去河邊找鬼躲惰。 笑死,一個胖子當著我的面吹牛变抽,可吹牛的內容都是我干的础拨。 我是一名探鬼主播,決...
    沈念sama閱讀 38,921評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼绍载,長吁一口氣:“原來是場噩夢啊……” “哼诡宗!你這毒婦竟也來了?” 一聲冷哼從身側響起逛钻,我...
    開封第一講書人閱讀 37,688評論 0 266
  • 序言:老撾萬榮一對情侶失蹤僚焦,失蹤者是張志新(化名)和其女友劉穎锰提,沒想到半個月后曙痘,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,130評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡立肘,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 36,467評論 2 325
  • 正文 我和宋清朗相戀三年边坤,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片谅年。...
    茶點故事閱讀 38,617評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡茧痒,死狀恐怖,靈堂內的尸體忽然破棺而出融蹂,到底是詐尸還是另有隱情旺订,我是刑警寧澤,帶...
    沈念sama閱讀 34,276評論 4 329
  • 正文 年R本政府宣布超燃,位于F島的核電站区拳,受9級特大地震影響,放射性物質發(fā)生泄漏意乓。R本人自食惡果不足惜樱调,卻給世界環(huán)境...
    茶點故事閱讀 39,882評論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望届良。 院中可真熱鬧笆凌,春花似錦、人聲如沸士葫。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,740評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽慢显。三九已至晦闰,卻和暖如春放祟,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背呻右。 一陣腳步聲響...
    開封第一講書人閱讀 31,967評論 1 265
  • 我被黑心中介騙來泰國打工跪妥, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人声滥。 一個月前我還...
    沈念sama閱讀 46,315評論 2 360
  • 正文 我出身青樓眉撵,卻偏偏與公主長得像,于是被迫代替她去往敵國和親落塑。 傳聞我的和親對象是個殘疾皇子纽疟,可洞房花燭夜當晚...
    茶點故事閱讀 43,486評論 2 348

推薦閱讀更多精彩內容

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 171,749評論 25 707
  • Android App的設計架構:MVC,MVP,MVVM與架構經(jīng)驗談1. 架構設計的目的1.1 通過設計使程序模...
    天空在微笑閱讀 4,145評論 1 20
  • 1、概述 Databinding 是一種框架憾赁,MVVM是一種模式污朽,兩者的概念是不一樣的。我的理解DataBindi...
    Kelin閱讀 76,773評論 68 521
  • 生活里食品有保質期龙考,藥品有有效期蟆肆,電器有保修期,房子有產(chǎn)權期晦款,所有物質的東西都有有效期炎功。那么父親母親的血液澆灌出的...
    雨雪菲閱讀 620評論 4 4
  • 感受晴天一樣的你 日出即明朗,日落即安詳 有時閑階小駐足缓溅,有時月色滿瀟湘 品味晴天一樣的你 白云亦舒卷蛇损,樹影亦婆娑...
    雨歇夢微涼閱讀 235評論 0 1