[AS2.3.3]MVVM模式學(xué)習(xí)(DataBinding庫(kù))

這邊算是對(duì)mvvm的學(xué)習(xí)記錄。大部分都來自網(wǎng)上!
先說下Data Binding的利弊

優(yōu)勢(shì)

DataBinding 出現(xiàn)以前,我們?cè)趯?shí)現(xiàn) UI 界面時(shí),不可避免的編寫大量的毫無營(yíng)養(yǎng)的代碼:比如View.findViewById();比如各種更新 View 屬性的 setter:setText()setVisibility()setEnabled() 或者setOnClickListener() 等等。
這些“垃圾代碼”數(shù)量越多,越容易滋生 bug。
使用 DataBinding,我們可以避免書寫這些“垃圾代碼”。

劣勢(shì)

使用 Data Binding 會(huì)增加編譯出的 apk 文件的類數(shù)量和方法數(shù)量。
新建一個(gè)空的工程,統(tǒng)計(jì)打開 build.gradle 中 Data Binding 開關(guān)前后的 apk 文件中類數(shù)量和方法數(shù)量,類增加了 120+,方法數(shù)增加了 9k+(開啟混淆后該數(shù)量減少為 3k+)。
如果工程對(duì)方法數(shù)量很敏感的話,請(qǐng)慎重使用 Data Binding。


1.基本MVVM使用

環(huán)境搭配

首先要讓Android Studio使用DataBinding庫(kù)才可以實(shí)現(xiàn)mvvm模式
在項(xiàng)目的主app項(xiàng)目Module內(nèi)加入DataBinding引用

apply plugin: 'com.android.application'

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

還有一個(gè)注意的就是

  • Android Studio版本在1.3以上
  • gradle的版本要在1.5.0-alpha1以上

基礎(chǔ)使用

在說使用之前我們需要將默認(rèn)的xml布局的最外層加入layout嵌套

<layout xmlns:android="http://schemas.android.com/apk/res/android">
    <data>
        <!--這邊設(shè)置data數(shù)據(jù)-->
        ......
    </data>
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:gravity="center"
        android:orientation="vertical">
            <!--這是原來的xml布局-->
            ........
      </LinearLayout>
</layout>

我們創(chuàng)建如下布局


布局
  • 對(duì)TextView EditText Button之類的設(shè)置文本
    先創(chuàng)建一個(gè)mvvmString類
public class mvvmString {
    private String str1;
    private String str2;
    private String str3;

    public mvvmString(String str1, String str2, String str3) {
        this.str1 = str1;
        this.str2 = str2;
        this.str3 = str3;
    }

    public String getStr1() {
        return str1;
    }

    public void setStr1(String str1) {
        this.str1 = str1;
    }

    public String getStr2() {
        return str2;
    }

    public void setStr2(String str2) {
        this.str2 = str2;
    }

    public String getStr3() {
        return str3;
    }

    public void setStr3(String str3) {
        this.str3 = str3;
    }
}

之后我們對(duì)xml布局進(jìn)行設(shè)置
首先是data

    <data>
        <variable name="string" type="com.gjn.msdemo.mvvm.mvvmString" />
    </data>

或者

    <data>
        <import type="com.gjn.msdemo.mvvm.mvvmString" />
        <variable name="string" type="mvvmString" />
    </data>

在data內(nèi)加入variable屬性設(shè)置名字和類型
之后我們就可以使用了,下面我們對(duì)TextView EditText Button分別設(shè)置

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

        <EditText
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:hint="@{string.str2}"
            android:ems="10"
            android:inputType="textPersonName" />

        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{string.str3}" />

之后我們對(duì)TestActivity進(jìn)行綁定數(shù)據(jù)和設(shè)置數(shù)據(jù)

public class TestActivity extends AppCompatActivity{
    private ActivityTestBinding binding;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        binding = DataBindingUtil.setContentView(this, R.layout.activity_test);

        binding.setString(new mvvmString("111","222","按鈕"));
    }
}

這邊提下,在哪個(gè)xml下面綁定就會(huì)生成相應(yīng)的Binding
好比這個(gè) R.layout.activity_test 他的生成是按照_進(jìn)行拼接形成ActivityTestBinding這個(gè)類

效果
  • 對(duì)ImageView設(shè)置圖片
    還是創(chuàng)建一個(gè)mvvmImage類
public class mvvmImage {
    @BindingAdapter({"image"})
    public static void imageLoader(ImageView imageView, String url){
        Glide.with(imageView.getContext()).load(url).into(imageView);
    }
}

這邊用了Glide來加載圖片
之后我們?cè)赿ata中加入新的類型

    <data>
        <import type="com.gjn.msdemo.mvvm.mvvmString" />
        <variable name="string" type="mvvmString" />
        <variable name="image" type="String" />
    </data>

        <ImageView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            app:image="@{image}" />

中間省略了 LinearLayout等布局
使用只需要在binding中加入設(shè)置的圖片即可

String url = "http://7xi8d6.com1.z0.glb.clouddn.com/20180109085038_4A7atU_rakukoo_9_1_2018_8_50_25_276.jpeg";
binding.setImage(url);
效果2
  • 對(duì)Button設(shè)置點(diǎn)擊事件
    還是先創(chuàng)建一個(gè)mvvmClick類
public class mvvmClick {

    public void onClick(View view){
        Toast.makeText(view.getContext(), "點(diǎn)擊", Toast.LENGTH_SHORT).show();
    }
}

之后設(shè)置data

    <data>
        <import type="com.gjn.msdemo.mvvm.mvvmString" />
        <variable name="string" type="mvvmString" />
        <variable name="image" type="String" />
        <variable name="click" type="com.gjn.msdemo.mvvm.mvvmClick" />
    </data>

        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:onClick="@{click.onClick}"
            android:text="@{string.str3}" />

中間省略了 LinearLayout等布局
在Activity中的使用如下

        binding.setClick(new mvvmClick());

點(diǎn)擊了按鈕就會(huì)彈出Toast


效果3

這樣就算是綁定了基本的數(shù)據(jù)了
下面貼下完整的Activity和xml布局的代碼

public class TestActivity extends AppCompatActivity{

    private ActivityTestBinding binding;

    private String url = "http://7xi8d6.com1.z0.glb.clouddn.com/" +
            "20180109085038_4A7atU_rakukoo_9_1_2018_8_50_25_276.jpeg";

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        binding = DataBindingUtil.setContentView(this, R.layout.activity_test);

        binding.setString(new mvvmString("111","222","按鈕"));

        binding.setImage(url);

        binding.setClick(new mvvmClick());

    }

}
<layout xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:android="http://schemas.android.com/apk/res/android">
    <data>
        <import type="com.gjn.msdemo.mvvm.mvvmString" />
        <variable name="string" type="mvvmString" />
        <variable name="image" type="String" />
        <variable name="click" type="com.gjn.msdemo.mvvm.mvvmClick" />
    </data>

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

        <ImageView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            app:image="@{image}" />

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

        <EditText
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:hint="@{string.str2}"
            android:ems="10"
            android:inputType="textPersonName" />

        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:onClick="@{click.onClick}"
            android:text="@{string.str3}" />

    </LinearLayout>
</layout>

2.MVVM進(jìn)階使用

  • BaseObservable的使用
    讓mvvmStrig繼承BaseObservable并改寫
public class mvvmString extends BaseObservable{
    private String str1;
    private String str2;
    private String str3;

    public mvvmString(String str1, String str2, String str3) {
        this.str1 = str1;
        this.str2 = str2;
        this.str3 = str3;
    }

    @Bindable
    public String getStr1() {
        return str1;
    }

    public void setStr1(String str1) {
        this.str1 = str1;
        notifyPropertyChanged(com.gjn.msdemo.BR.str1);
    }

    @Bindable
    public String getStr2() {
        return str2;
    }

    public void setStr2(String str2) {
        this.str2 = str2;
        notifyPropertyChanged(com.gjn.msdemo.BR.str2);
    }

    @Bindable
    public String getStr3() {
        return str3;
    }

    public void setStr3(String str3) {
        this.str3 = str3;
        notifyPropertyChanged(com.gjn.msdemo.BR.str3);
    }
}

即對(duì)get數(shù)據(jù)進(jìn)行Bindabel,設(shè)置屬性之后調(diào)用刷新方法notifyPropertyChanged

這時(shí)候修改數(shù)據(jù)就只要

        mvvmString string = new mvvmString("111","222","按鈕");
        binding.setString(string);
        string.setStr1("333");
        string.setStr2("444");
        string.setStr3("按鈕2");

就可以修改了。否則如果沒有繼承BaseObservable的話,修改數(shù)據(jù)是需要
如下操作

        mvvmString string = new mvvmString("111","222","按鈕");
        binding.setString(string);
        string.setStr1("333");
        string.setStr2("444");
        string.setStr3("按鈕2");
        binding.setString(string);

就是重新再綁定一次,BaseObservable只是加入了刷新
但是BaseObservable這個(gè)方法還是太麻煩了,如果類多了。每個(gè)類都寫一個(gè)M綁定...實(shí)在是累人

  • ObservableField的使用
    創(chuàng)建新的mvvmString2
public class mvvmString2 {
    public final ObservableField<String> str1 = new ObservableField<>();
    public final ObservableField<String> str2 = new ObservableField<>();
    public final ObservableField<String> str3 = new ObservableField<>();
}

修改 data使用

    <data>
        <import type="com.gjn.msdemo.mvvm.mvvmString2" />
        <variable name="string" type="mvvmString2" />
        <variable name="image" type="String" />
        <variable name="click" type="com.gjn.msdemo.mvvm.mvvmClick" />
    </data>

使用如下

        mvvmString2 string2 = new mvvmString2();
        binding.setString(string2);
        string2.str1.set("text");
        string2.str2.set("edit");
        string2.str3.set("button");

這樣對(duì)創(chuàng)建M也方便,并且設(shè)置也很快捷

  • BindingAdapter的使用
    上面在修改圖片的時(shí)候用到了BindingAdapter,這邊就在來具體說下BindingAdapter的使用

首先我們先新建一個(gè)xml布局
act_test_adapter.xml

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">
    <data>
        <variable name="adapter" type="com.gjn.msdemo.mvvm.mvvmAdapter" />
    </data>

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

        <Button
            android:id="@+id/button"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:onClick="@{adapter.add}"
            android:text="add" />

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:orientation="vertical"
            app:texts="@{adapter.texts}" />
    </LinearLayout>

</layout>

我們還創(chuàng)建了一個(gè)新的mvvmAdapter類

public class mvvmAdapter {
    public ObservableArrayList<String> texts = new ObservableArrayList<>();
    
    public mvvmAdapter(){
        for (int i = 0; i < 5; i++) {
            texts.add("text => " + i);
        }
    }

    @BindingAdapter({"texts"})
    public static void addTextView(LinearLayout linearLayout, ArrayList<String> texts){
        linearLayout.removeAllViews();

        for (String text : texts) {
            TextView textView = new TextView(linearLayout.getContext());
            textView.setText(text);
            linearLayout.addView(textView);
        }

    }

    public void add(View v){
        texts.add("new text");
    }
}

之后修改TestActivity

public class TestActivity extends AppCompatActivity{

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        ActTestAdapterBinding binding = DataBindingUtil.setContentView(this,R.layout.act_test_adapter);
        binding.setAdapter(new mvvmAdapter());
    }
}

實(shí)現(xiàn)效果如下


點(diǎn)擊效果

還有一些使用說明

  • 自定義Binding名
    首先我們創(chuàng)建的Bingding都是按照xml生成的,如果我們不希望這樣生成可以修改data,在里面加入class屬性
    例如
    <data class="NewBinding">
        <variable name="adapter" type="com.gjn.msdemo.mvvm.mvvmAdapter" />
    </data>
  • 別名
    可以再使用導(dǎo)包的時(shí)候設(shè)置別名,這樣有利于區(qū)分一些差不多命名的包,就是在import 加入屬性alias
    <data class="NewBinding">
        <import type="com.gjn.msdemo.mvvm.mvvmAdapter" alias="testadapter" />
        <variable name="adapter" type="testadapter" />
    </data>
  • 在屬性設(shè)置的時(shí)候要加入包
    如果想設(shè)置一些屬性
    例如我想設(shè)置view的顯示屬性
    稍微對(duì)上面的mvvmAdapter進(jìn)行修改。這邊就貼修改的代碼
mvvmAdapter 
public class mvvmAdapter {
    public final ObservableField<Boolean> isView = new ObservableField<>();
}

xml
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">
    <data class="NewBinding">
        <import type="com.gjn.msdemo.mvvm.mvvmAdapter" alias="testadapter" />
        <import type="android.view.View" />
        <variable name="adapter" type="testadapter" />
    </data>
        <!-- 其他布局-->
        <Button
            android:id="@+id/button"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:onClick="@{adapter.add}"
            android:visibility="@{adapter.isView ? View.VISIBLE : View.GONE}"
            android:text="add" />
        <!-- 其他布局-->
</layout>

activity
public class TestActivity extends AppCompatActivity{

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

//        ActTestAdapterBinding binding = DataBindingUtil.setContentView(this,R.layout.act_test_adapter);
        NewBinding binding = DataBindingUtil.setContentView(this,R.layout.act_test_adapter);
        mvvmAdapter adapter = new mvvmAdapter();
        binding.setAdapter(adapter);
        adapter.isView.set(false);
    }

}
新效果

資料

【Android】DataBinding庫(kù)(MVVM設(shè)計(jì)模式)
安卓 Data Binding 使用方法總結(jié)(姐姐篇)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,327評(píng)論 6 537
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,996評(píng)論 3 423
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 177,316評(píng)論 0 382
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,406評(píng)論 1 316
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 72,128評(píng)論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,524評(píng)論 1 324
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,576評(píng)論 3 444
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,759評(píng)論 0 289
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,310評(píng)論 1 335
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 41,065評(píng)論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 43,249評(píng)論 1 371
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,821評(píng)論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,479評(píng)論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,909評(píng)論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,140評(píng)論 1 290
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 51,984評(píng)論 3 395
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 48,228評(píng)論 2 375