Android架構(gòu)模式-MVVM-DataBinding

MVVM(Model - View - ViewModel)最初是在2005年由微軟提出的一個(gè)UI框架的概念。相比MVP模式,MVVM將Presenter改為了ViewModel,同時(shí)實(shí)現(xiàn)的View和ViewModel的雙向數(shù)據(jù)綁定,View層的變化會(huì)自動(dòng)導(dǎo)致ViewModel發(fā)生變化,ViewModel的數(shù)據(jù)發(fā)生變化也會(huì)自動(dòng)實(shí)現(xiàn)View的刷新,開發(fā)者可以不用直接處理View和數(shù)據(jù)的更新操作,MVVM框架會(huì)完成這一切,MVVM模式不同層關(guān)系如下


Data Binding

在Google I/O2015大會(huì)上,Android開發(fā)團(tuán)隊(duì)發(fā)布了官方的MVVM支持函數(shù)庫(kù)Data Binding Library,要求,Gradle的版本大于1.5.0-alphal,Android最低版本Android4.0

Databinding 是一個(gè)實(shí)現(xiàn)數(shù)據(jù)和UI綁定的框架,是一個(gè)實(shí)現(xiàn) MVVM 模式的工具,有了 Data Binding,在Android中也可以很方便的實(shí)現(xiàn)MVVM開發(fā)模式。
官網(wǎng)

起步

  • 配置Gradle
    在app/在build.gradle使用如下配置
    android {
        ...
        dataBinding {
            enabled = true
        }
    }
    
  • 數(shù)據(jù)綁定
    使用 @{} 語(yǔ)法可以輕松綁定數(shù)據(jù)
    <TextView
            android:text="@{model.userName}"/>
    

數(shù)據(jù)綁定

  • 布局文件(View)
    Data binding 的布局文件與傳統(tǒng)布局文件有一點(diǎn)不同。它以一個(gè) layout 標(biāo)簽作為根節(jié)點(diǎn),里面是 data 標(biāo)簽與 view 標(biāo)簽。view 標(biāo)簽的內(nèi)容就是不使用 Data Binding 時(shí)的普通布局文件內(nèi)容
    <?xml version="1.0" encoding="utf-8"?>
    <layout xmlns:android="http://schemas.android.com/apk/res/android">
       <data>
           <variable name="book" type="app.mrquan.databindingdemo.pojo.Book"/>
       </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="@{book.name}"/>
           <TextView android:layout_width="wrap_content"
               android:layout_height="wrap_content"
               android:text="@{String.valueOf(book.price)}"/>
       </LinearLayout>
    </layout>
    
  • 數(shù)據(jù)對(duì)象(Model)
    public class Book {
        public String name;
        public Integer price;
    
        public Book(String name, Integer price) {
            this.name = name;
            this.price = price;
        }
        /**
         * Constructor
         * ...
         */
    }
    
    public class Book {
        private String name;
        private Integer price;
    
        public Book(String name, Integer price) {
            this.name = name;
            this.price = price;
        }
        /**
         * Constructor
         * getter setter
         * ...
         */
    }
    
    從 Data Binding 的角度看,這兩個(gè)類是一樣的。
    在前一個(gè)類中表達(dá)式 @{book.name} 用于 android:text 訪問(wèn) name 屬性,在后一個(gè)類中用于訪問(wèn) getName() 方法。 另外,兩者都存在,它會(huì)優(yōu)先解析為 getName() 方法。
  • 綁定數(shù)據(jù)(ViewModel)
    在默認(rèn)情況下,會(huì)基于布局文件生成一個(gè)繼承于ViewDataBindingBinding 類。例如,布局文件叫 main_activity.xml,所以會(huì)生成一個(gè) MainActivityBinding 類。這個(gè)類包含了布局文件中所有的綁定關(guān)系,會(huì)根據(jù)綁定表達(dá)式給布局文件賦值。綁定方式如下
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        //  ActivityMainBinding 類是自動(dòng)生成的
        ActivityMainBinding binding = DataBindingUtil.setContentView(this,R.layout.activity_main);
        // 所有的 set 方法也是根據(jù)布局中 variable 名稱生成的
        binding.setBook(new Book("Thinking in JAVA",100));
    }
    
  • 表達(dá)式語(yǔ)言
    data binding提供了大量的表達(dá)式方法 鏈接

事件處理

有兩種實(shí)現(xiàn)方式:

  • 方法引用(Method References)

  • 監(jiān)聽綁定(Listener bindings)

    方法引用和監(jiān)聽綁定之間的主要區(qū)別在于監(jiān)聽器是在綁定數(shù)據(jù)時(shí)創(chuàng)建的,而不是在觸發(fā)事件時(shí)創(chuàng)建的。如果希望在事件觸發(fā)時(shí)解析表達(dá)式,則應(yīng)使用監(jiān)聽綁定

    方法引用

    事件可以直接綁定到處理函數(shù)方法,類似于activity的android:onClick. 它的優(yōu)勢(shì)在于表達(dá)式會(huì)在編譯時(shí)處理,如果函數(shù)不存在或者函數(shù)簽名不對(duì),編譯將會(huì)報(bào)錯(cuò)。方法引用如下

    public class MyHandler {
        public void onClick( View view ) { ... }
    }
    
    <?xml version="1.0" encoding="utf-8"?>
    <layout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools">
        <data>
            <variable name="book" type="app.mrquan.databindingdemo.pojo.Book"/>
            <variable name="handler" type="app.mrquan.databindingdemo.MyHandler"/>
        </data>
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:orientation="vertical"
            tools:context=".MainActivity">
            <TextView
                android:layout_width="match_parent"
                android:layout_height="0dp"
                android:layout_weight="1"
                android:text="@{book.name}"
                android:onClick="@{handler::onClick}"/>
                <!-- 函數(shù)調(diào)用也可以使用 `.` , 如handler.onClickFriend , 不過(guò)已棄用 -->
        </LinearLayout>
    </layout>
    

    注:表達(dá)式中方法名必須與監(jiān)聽器對(duì)象中方法名完全一致。

    監(jiān)聽綁定

    在監(jiān)聽綁定中,只要返回值與監(jiān)聽器對(duì)象的預(yù)期返回值相匹配即可??梢允褂脦в卸鄠€(gè)參數(shù)的lambda表達(dá)式,監(jiān)聽綁定如下

    public class MyHandler {
        public void onClickTwo(View view, Book book) { ... }
    }
    
    <Button
        android:text="監(jiān)聽綁定"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"
        android:onClick="@{(view) -> handler.onClickTwo(view,book)}" />
    

    注:此功能在 Android Gradle Plugin version 2.0 或更新版本上可用.

深入Layout文件

  • 導(dǎo)入(Imports)
    data 標(biāo)簽內(nèi)可以有多個(gè) import 標(biāo)簽。可以在布局文件中像使用 Java 一樣導(dǎo)入引用
    <data>
        <import type="android.view.View"/>
    </data>
    
    <TextView
       android:text="@{user.lastName}"
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"
       android:visibility="@{user.isAdult ? View.VISIBLE : View.GONE}"/>
    
    當(dāng)類名發(fā)生沖突時(shí),可以使用 alias
    <import type="com.example.real.estate.View" alias="Vista"/>
    
  • includes
    引用變量可以傳遞到任何include布局中如下
    <?xml version="1.0" encoding="utf-8"?>
    <layout xmlns:android="http://schemas.android.com/apk/res/android"
            xmlns:bind="http://schemas.android.com/apk/res-auto">
       <data>
           <variable name="user" type="com.example.User"/>
       </data>
       <LinearLayout
           android:orientation="vertical"
           android:layout_width="match_parent"
           android:layout_height="match_parent">
           <include layout="@layout/name"
               bind:user="@{user}"/>
           <include layout="@layout/contact"
               bind:user="@{user}"/>
       </LinearLayout>
    </layout>
    
    注:name.xml 與 contact.xml 中都需要聲明 user 變量。
  • Data Binding 進(jìn)階
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容