When it comes to actually touching and using the MVVM architecture, the whole person is no good. Because personally, COMPARED with MVC and MVP, MVVM is more difficult to learn, and the knowledge of design is not the slightest bit. So I want to slowly record my growth. Please correct any mistakes.


Building an MVVM Architecture from Scratch series of articles (continuing updates) : Android builds MVVM from scratch (1) ————DataBinding Android builds MVVM from scratch (2) ————ViewModel Android builds MVVM from scratch (3) ————LiveData Android builds MVVM architecture from scratch (4) ————Room (from beginner to advanced) Android builds MVVM architecture from scratch (5) ————Lifecycles Android builds MVVM architecture from scratch (6) ———— Uses Android to play ———— Use the Android API to take you to build the MVVM framework (final)


AAC(Android Architecture Components)

In this article we will cover the LiveData component


A, LiveData

First, let’s briefly introduce LiveData, its functions and characteristics. I’ll prove it with an example.

LiveData is a life-cycle aware and observable data holder class. 2. When the life cycle is onStop or onPause, the data update is not called back. When the life cycle is onDestory, the observer is automatically deleted to prevent memory overflow. 4. Share resources. You can use the singleton pattern to extend LiveData objects to wrap system services so that they can be shared across applications while complying with the above lifecycle

LiveData has two methods for notifying data changes:

  • Synchronization:.setValue (value) The data callback on the receiving end is on the same thread as that on the sending end
  • Asynchronous:.postValue (value) The receiver calls back data on the main thread


Simple LiveData usage and differences with DataBinding bidirectional DataBinding

2.1. Simple use of LiveData

To make the difference, I’ll use a TextView as the title to make it clear. The XML looks like this. (If you don’t understand the DataBinding usage advice, start with the previous articles.)

<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="Set data using LiveData alone:"
                />

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

        </LinearLayout>

    </LinearLayout>
</layout>
Copy the code


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());
        
        // Data change listener
        liveData.observe(this.new Observer<String>() {
            @Override
            public void onChanged(String s) {
                binding.setOnlyLive(s);
                LogUtils.i("Watch LiveData." "."Use LiveData alone ==>"+ s); }}); }@Override
    protected void onStop(a) {
        super.onStop();
        liveData.postValue("Use LiveData alone"); }}Copy the code


  • LiveData is an observable data holder class. So there’s a monitor that looks for changes in the data
// The first parameter is LifeCycleOwner. So that's another component of ours.
// As mentioned in the DataBinding article, in the Support library after version 26,
LifecycleOwner is implemented on AppCompatActivity and SupportActivity, and the UI lifecycle is already handled internally.
// LiveData is a LiveData
/ / 2,
liveData.observe(this.new Observer<String>() {
            @Override
            public void onChanged(String s) { binding.setOnlyLive(s); ToastUtils.showToast(s); }});Copy the code


  • LiveData is a life cycle awareness. Only when LiveData is active and its life cycle is onStart and onResume, the updated data will be notified to the corresponding Activity. When the life cycle is onStop or onPause, data updates are not called back until the life cycle is onResume. When the life cycle is in onDestory, the observer is automatically deleted to prevent memory overflow
    // For his life cycle awareness, we press the home button and set his data as follows when leaving the view. And look at the effect
    @Override
    protected void onStop(a) {
        super.onStop();
        liveData.postValue("Use LiveData alone");
    }
Copy the code


The effect picture is as follows (press the home button to enter the background and then cut in) :


2.2. Differences with DataBinding two-way DataBinding

To see LiveData, you also need to set the data to the XML by listening. DataBinding’s DataBinding is more convenient. So let’s add DataBinding’s two-way DataBinding. Create a test class using our ObservableField.

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

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


XML is as follows:

<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="Set data using LiveData alone:"
                />

            <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 bidirectional DataBinding setting data:"
                />

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


In the Activity, because DataBinding’s DataBinding does not have a watch on it, we do a listen on the textView that sets the data.

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(a) {
        binding.txtOnlyLive.addTextChangedListener(new TextWatcher() {
            ....// Omit some code
            @Override
            public void afterTextChanged(Editable s) {
                LogUtils.i("TextView changes"."Use LiveData alone ==>"+ s); }}); binding.txtDataBinding.addTextChangedListener(new TextWatcher() {
            ....// Omit some code
            @Override
            public void afterTextChanged(Editable s) {
                LogUtils.i("TextView changes"."DataBinding bidirectional binding ==>"+ s); }}); }@Override
    protected void onStop(a) {
        super.onStop();
        liveData.postValue("Use LiveData alone");
        testBean.name.set("I'm DataBinding bidirectional binding"); }}Copy the code

Also set the data when leaving the interface: the effect picture is as follows (see the print) :

  • You can see an exit. The DataBinding two-way DataBinding is set to the TextView. There are many potential bugs that don’t follow the lifecycle, which is why google-generated components follow the lifecycle.
  • And LiveData every time to write listening, how can Google tolerate. Here’s where LifecycleOwner gets powerful

LiveData is used with ViewModel

LifecycleOwner was mentioned in the previous article. Even if LiveData is used in conjunction with the ViewModel, it should be used to eliminate the need to listen every time the data changes

How do you use it?

The key is to set our DataBingding LifecycleOwner: binding. SetLifecycleOwner (this);


So let’s look at our ViewModel

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

    public MutableLiveData<String> getData(a) {
        returnnameLiveData; }}Copy the code


Add a piece of data to display the ViewModel in the 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" />

        <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="Set data using LiveData alone:"
                />

            <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 bidirectional DataBinding setting data:"
                />

            <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 with LiveData set data:
                />

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

        </LinearLayout>


    </LinearLayout>
</layout>
Copy the code


In the 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);
        
        // This section focuses on the following two lines of code
        binding.setLifecycleOwner(this);
        model = ViewModelProviders.of(this).get(LiveDataViewModel.class);
        
        binding.setLiveViewModel(model);
        addLiveObserve();
        addTextViewChange();

    }

    private void addTextViewChange(a) {
        binding.txtOnlyLive.addTextChangedListener(new TextWatcher() {
            .../ / to omit
            @Override
            public void afterTextChanged(Editable s) {
                LogUtils.i("TextView changes"."Use LiveData alone ==>"+ s); }}); binding.txtDataBinding.addTextChangedListener(new TextWatcher() {
            .../ / to omit
            @Override
            public void afterTextChanged(Editable s) {
                LogUtils.i("TextView changes"."DataBinding bidirectional binding ==>"+ s); }}); binding.txtViewmodelLivedata.addTextChangedListener(new TextWatcher() {
            .../ / to omit
            @Override
            public void afterTextChanged(Editable s) {
                LogUtils.i("TextView changes"."ViewModel with LiveData ==>"+ s); }}); }private void addLiveObserve(a) {
        liveData.observe(this.new Observer<String>() {
            @Override
            public void onChanged(String s) {
                // Use it alone.binding.setOnlyLive(s); }}); }@Override
    protected void onStop(a) {
        super.onStop();
        liveData.postValue("Use LiveData alone");
        testBean.name.set("I'm DataBinding bidirectional binding");
        model.getData().postValue("ViewModel with LiveData"); }}Copy the code

Model.getdata ().postValue(“ViewModel with LiveData “); Change the data in the ViewModel and look at the result:

Here is a brief introduction to the simple LiveData, and use. Let’s slowly implement our own MVVM framework!!

Demo address