Android从零开始搭建MVVM架构(3)————LiveData

9,060 阅读7分钟

在真正接触并使用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组件


一、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里的数据,看结果:

结果发现DataBinding双向绑定也跟随生命周期了。LiveData配合ViewModel使用,不用监听也能绑定数据了。厉害了

至此这里对简单的LiveData做了简单介绍,和使用。让我们一起慢慢实现自己的MVVM框架把!!

本文demo地址