Android從零開始搭建MVVM架構(3)————LiveData

在真正接觸並使用MVVM架構的時候,整個人都不好了。因爲個人覺得,MVVM相對於MVC、MVP學習難度比較大,設計的知識點不是一點半點。所以想慢慢記錄下自己的成長。如有錯誤希望指正。

從零開始搭建MVVM架構系列文章(持續更新):
Android從零開始搭建MVVM架構(1)————DataBinding
Android從零開始搭建MVVM架構(2)————ViewModel
Android從零開始搭建MVVM架構(3)————LiveData
Android從零開始搭建MVVM架構(4)————Room(從入門到進階)
Android從零開始搭建MVVM架構(5)————Lifecycles
Android從零開始搭建MVVM架構(6)————使用玩Android API帶你搭建MVVM框架(初級篇)
Android從零開始搭建MVVM架構(7) ———— 使用玩Android API帶你搭建MVVM框架(終極篇)

還是那張圖AAC(Android Architecture Components)

這篇我們講LiveData。這裏我們只是簡單瞭解和認識MVVM中的LiveData組件


一、LiveData

首先我們把簡單介紹下LiveData極其作用和特點。後面用例子來證明。

簡介:LiveData 是一個有生命週期感知 & 可觀察的數據持有者類
作用
持久化的觀察數據的更改與變化
特點
1、感知對應Activity的生命週期,只有生命週期處於onStart與onResume時,LiveData處於活動狀態,纔會把更新的數據通知至對應的Activity
2、當生命週期處於onStop或者onPause時,不回調數據更新,直至生命週期爲onResume時,立即回調
3、當生命週期處於onDestory時,觀察者會自動刪除,防止內存溢出
4、共享資源。可以使用單例模式擴展LiveData對象以包裝系統服務,以便可以在應用程序中共享它們,同時有遵守了以上生命週期

LiveData有2個方法通知數據改變:

  • 同步:.setValue(value)接收端數據回調與發送端同一個線程
  • 異步:.postValue(value)接收端在主線程回調數據

二、簡單LiveData使用及與DataBinding雙向數據綁定的區別

2.1、簡單LiveData使用

因爲要做區別,我這裏先用一個TextView做標題,看起來清晰些,xml如下(如果不理解DataBinding使用的建議,從前幾篇文章開始看)

<layout xmlns:android="http://schemas.android.com/apk/res/android">

    <data>

        <variable
            name="onlyLive"
            type="String" />

    </data>

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

        <LinearLayout
            android:layout_marginTop="30dp"
            android:orientation="horizontal"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content">
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="單獨使用LiveData設置數據:"
                />

            <TextView
                android:id="@+id/txt_only_live"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="@{onlyLive}"
                />

        </LinearLayout>

    </LinearLayout>
</layout>

Activity裏的代碼:
public class LiveDataActivity extends AppCompatActivity {
    ActivityLivedataBinding binding;
    private MutableLiveData<String> liveData = new MutableLiveData<>();

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_livedata);
        binding = DataBindingUtil.setContentView(this, R.layout.activity_livedata);
        binding.setOnlyLive(liveData.getValue());
        
        //數據改變監聽
        liveData.observe(this, new Observer<String>() {
            @Override
            public void onChanged(String s) {
                binding.setOnlyLive(s);
                LogUtils.i("觀察LiveData", "單獨使用LiveData ==> " + s);
            }
        });
    }

    @Override
    protected void onStop() {
        super.onStop();
        liveData.postValue("單獨LiveData使用");
    }
}


  • LiveData 是一個可觀察的數據持有者類。所以有一個觀察數據變化的監聽
//1、第一個參數是LifeCycleOwner。這樣也是我們另外一個組件.
//  在DataBinding篇,也說了,在26版本以後的Support庫中,
//  AppCompatActivity和SupportActivity中都實現了LifecycleOwner,內部已經對UI界面的生命週期做了處理了。
//  這裏我們學習的是LiveData,先暫且把他忽略調
//2、
liveData.observe(this, new Observer<String>() {
            @Override
            public void onChanged(String s) {
                binding.setOnlyLive(s);
                ToastUtils.showToast(s);
            }
        });

  • LiveData 是一個有生命週期感知。只有生命週期處於onStart與onResume時,LiveData處於活動狀態,纔會把更新的數據通知至對應的Activity;當生命週期處於onStop或者onPause時,不回調數據更新,直至生命週期爲onResume時,立即回調;當生命週期處於onDestory時,觀察者會自動刪除,防止內存溢出
    //針對他的生命週期感知,我們在按home鍵,在離開視圖界面的時候給他設置數據如下。然後看效果
    @Override
    protected void onStop() {
        super.onStop();
        liveData.postValue("單獨LiveData使用");
    }

效果圖如下(按home鍵,程序進入後臺後再切進去)


2.2、與DataBinding雙向數據綁定的區別

看到LiveData還需要通過監聽給xml設置數據。這個時候我們會不由的想起DataBinding的數據綁定,豈不是比他方便。那麼我加上DataBinding的雙向數據綁定看看。建一個測試類,用到我們的ObservableField(不清楚的去看前幾篇)

public class TestBean {
    public final ObservableField<String> name = new ObservableField<>();

    private void setName(String name) {
        this.name.set(name);
    }
}

xml如下:

<layout xmlns:android="http://schemas.android.com/apk/res/android">

    <data>

        <variable
            name="onlyLive"
            type="String" />

        <variable
            name="dataBsource"
            type="com.lihang.viewmodelstu.bean.TestBean" />

    </data>

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

        <LinearLayout
            android:layout_marginTop="30dp"
            android:orientation="horizontal"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content">
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="單獨使用LiveData設置數據:"
                />

            <TextView
                android:id="@+id/txt_only_live"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="@{onlyLive}"
                />

        </LinearLayout>


        <LinearLayout
            android:layout_marginTop="30dp"
            android:orientation="horizontal"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content">
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="DataBinding雙向數據綁定設置數據:"
                />

            <TextView
                android:id="@+id/txt_dataBinding"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="@={dataBsource.name}"
                />
        </LinearLayout>
    </LinearLayout>
</layout>

Activity裏,因爲DataBinding的數據綁定沒有觀察監聽,那我們就對設置數據的textView做個監聽。

public class LiveDataActivity extends AppCompatActivity {
    ActivityLivedataBinding binding;
    private MutableLiveData<String> liveData = new MutableLiveData<>();
    private TestBean testBean = new TestBean();

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_livedata);
        binding = DataBindingUtil.setContentView(this, R.layout.activity_livedata);
        binding.setOnlyLive(liveData.getValue());
        binding.setDataBsource(testBean);
        addTextViewChange();

    }

    private void addTextViewChange() {
        binding.txtOnlyLive.addTextChangedListener(new TextWatcher() {
            ....//省略部分代碼
            @Override
            public void afterTextChanged(Editable s) {
                LogUtils.i("TextView的變化", "單獨使用LiveData ==> " + s);
            }
        });


        binding.txtDataBinding.addTextChangedListener(new TextWatcher() {
            ....//省略部分代碼
            @Override
            public void afterTextChanged(Editable s) {
                LogUtils.i("TextView的變化", "DataBinding雙向綁定 ==> " + s);
            }
        });
    }

    @Override
    protected void onStop() {
        super.onStop();
        liveData.postValue("單獨LiveData使用");
        testBean.name.set("我是DataBinding雙向綁定");
    }
}

同樣在離開界面的時候設置下數據:
效果圖如下(我們看打印)

  • 可以看到一退出。DataBinding的雙向數據綁定就設置到TextView上了。沒有跟着生命期走,那麼潛在的bug也是很多的,這也是爲什麼google出的組件都是跟隨生命週期走的。
  • 而LiveData每次都要去寫監聽,google怎麼會忍受。LifecycleOwner強大之處來了

三、LiveData配合ViewModel使用

上篇提到了LifecycleOwner。即使LiveData配合ViewModel使用,也要通過它來省去每次數據改變的監聽

怎麼用呢?

關鍵就是給我們的DataBingding設置LifecycleOwner:binding.setLifecycleOwner(this);


來看我們的ViewModel

public class LiveDataViewModel extends ViewModel {
    private MutableLiveData<String> nameLiveData = new MutableLiveData<>();

    public MutableLiveData<String> getData() {
        return nameLiveData;
    }

}

xml裏再加上一條顯示ViewModel的數據

<layout xmlns:android="http://schemas.android.com/apk/res/android">

    <data>

        <variable
            name="onlyLive"
            type="String" />

        <variable
            name="dataBsource"
            type="com.lihang.viewmodelstu.bean.TestBean" />

        <variable
            name="liveViewModel"
            type="com.lihang.viewmodelstu.viewmodel.LiveDataViewModel" />

    </data>

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

        <LinearLayout
            android:layout_marginTop="30dp"
            android:orientation="horizontal"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content">
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="單獨使用LiveData設置數據:"
                />

            <TextView
                android:id="@+id/txt_only_live"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="@{onlyLive}"
                />

        </LinearLayout>


        <LinearLayout
            android:layout_marginTop="30dp"
            android:orientation="horizontal"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content">
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="DataBinding雙向數據綁定設置數據:"
                />

            <TextView
                android:id="@+id/txt_dataBinding"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="@={dataBsource.name}"
                />
        </LinearLayout>

        <LinearLayout
            android:layout_marginTop="30dp"
            android:orientation="horizontal"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content">
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="ViewModel配合LiveData設置數據:"
                />

            <TextView
                android:id="@+id/txt_viewmodel_livedata"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="@{liveViewModel.data}"
                />

        </LinearLayout>


    </LinearLayout>
</layout>

Activity裏:

public class LiveDataActivity extends AppCompatActivity {
    ActivityLivedataBinding binding;
    private MutableLiveData<String> liveData = new MutableLiveData<>();
    private TestBean testBean = new TestBean();
    private LiveDataViewModel model;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_livedata);
        binding = DataBindingUtil.setContentView(this, R.layout.activity_livedata);
        binding.setOnlyLive(liveData.getValue());
        binding.setDataBsource(testBean);
        
        //本節重點是下面2句代碼哦
        binding.setLifecycleOwner(this);
        model = ViewModelProviders.of(this).get(LiveDataViewModel.class);
        
        binding.setLiveViewModel(model);
        addLiveObserve();
        addTextViewChange();

    }

    private void addTextViewChange() {
        binding.txtOnlyLive.addTextChangedListener(new TextWatcher() {
            ...//省略
            @Override
            public void afterTextChanged(Editable s) {
                LogUtils.i("TextView的變化", "單獨使用LiveData ==> " + s);
            }
        });


        binding.txtDataBinding.addTextChangedListener(new TextWatcher() {
            ...//省略
            @Override
            public void afterTextChanged(Editable s) {
                LogUtils.i("TextView的變化", "DataBinding雙向綁定 ==> " + s);
            }
        });


        binding.txtViewmodelLivedata.addTextChangedListener(new TextWatcher() {
            ...//省略
            @Override
            public void afterTextChanged(Editable s) {
                LogUtils.i("TextView的變化", "ViewModel配合LiveData使用 ==> " + s);
            }
        });
    }
    
    private void addLiveObserve() {
        liveData.observe(this, new Observer<String>() {
            @Override
            public void onChanged(String s) {
                //單獨使用的還是需要監聽哦!
                binding.setOnlyLive(s);
            }
        });
    }
    
    @Override
    protected void onStop() {
        super.onStop();
        liveData.postValue("單獨LiveData使用");
        testBean.name.set("我是DataBinding雙向綁定");
        model.getData().postValue("ViewModel配合LiveData使用");
    }
}

我們通過model.getData().postValue(“ViewModel配合LiveData使用”);去改變ViewModel裏的數據,看結果:

至此這裏對簡單的LiveData做了簡單介紹,和使用。讓我們一起慢慢實現自己的MVVM框架把!!

本文demo地址

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章