Android|Android jetpack - LiveData 可观察数据存储类

一、前言 LiveData 可观察数据存储类属于谷歌在2018推出Android jetpack(外网)其中的软件架构组件中的一个。在谷歌开发者网站有详细介绍LiveData(外网)。本文以总结为目的,采用更加清晰和有条理的方式解读LiveData。
阅读前准备
便于理解,如果你已经知道什么是Lifecycle、观察者模式和ViewModel 更好,那么理解此篇文章便轻车熟路。
避免过多而杂的介绍,部分知识不详述,请阅读笔者链接文章或者Google。
全文就一个核心
LiveData是结合Lifecycle和观察者模式的数据存储类
二、LiveData 谷歌爸爸的介绍
LiveData是一种可观察的数据存储器类。与常规的可观察类不同,LiveData 具有生命周期感知能力,意指它遵循其他应用组件(如 Activity、Fragment 或 Service)的生命周期。这种感知能力可确保 LiveData 仅更新处于活跃生命周期状态的应用组件观察者。
简单理解
LiveData就是结合生命周期+观察者模式的数据存储类。方便我们根据生命周期来监听数据变化的。由于这个结构的特性,所以它拥有以下特点
1、确保界面符合数据状态;2、不会发生内存泄露;3、不会因 Activity 停止而导致崩溃;4、不再需要手动处理生命周期;5、数据始终保持最新状态;6、适当的配置更改;7、共享资源
【Android|Android jetpack - LiveData 可观察数据存储类】导入

implementation "androidx.lifecycle:lifecycle-viewmodel:$lifecycle_version"

三、详细介绍 LiveData介绍就如下几个点
  • LiveData基本使用
  • LiveData自定义LiveData
  • LiveDa数据转换
  • LiveData合并多个数据
3.1、基本使用 这里说下为啥别的文章或者官网都是结合ViewModel来讲的例子,ViewModel就是存储和管理界面数据的一个类。我们LiveData就是一种数据。如果不和ViewModel一起讲,不影响我们理解LiveData的核心思想。但是并不推荐直接在Activity或者Fragment里直接写LiveData变量来存储数据。这会让他们过于臃肿,所以还是用推荐存储数据的方式ViewModel。
如果你还不了解ViewModel你可以简单理解为它就是存储数据的一个地方。
LiveData在使用上除了和ViewModel结合以外无非观察者模式三个步骤
  • 创建LiveData,即创建被观察者
  • 添加Observe,添加观察者
  • 数据改变是修改UI,观察者监听
public class MyViewModel extends ViewModel { MutableLiveData name; public MutableLiveData getName() { if (name == null) { name = new MutableLiveData<>(); } return name; } }ViewModelProvider.Factory factory = ViewModelProvider.AndroidViewModelFactory.getInstance(this.getApplication()); ViewModelProvider viewModelProvider = new ViewModelProvider(this, factory); viewModel = viewModelProvider.get(MyViewModel.class); viewModel.getName().observe(this, new Observer() { @Override public void onChanged(String s) { textView.setText(s); } }); viewModel.getName().setValue("yink");

1、MyViewModel就是我们创建LiveData的地方。
2、viewModel.getName()拿到LiveData对象,observer添加观察者,this是Lifecycle生命周期组件。
3、当数据变化setValue时,会自动调用观察者的onChanged方法,我们就可以更新UI或其它操作了。
  • 其中在理解ViewModel上可不必太追究细节,理解为创建对象即可
  • 至于observe的参数this参数,带入的是Lifecycle,不太理解生命周期请移步Lifecycle
  • 为啥用MutableLiveData对象是因为MutableLiveData提供set,get方法。而LiveData只对外开放get方法,LiveData的set,get代码如下:
protected void setValue(T value) {public T getValue() {

3.2、自定义LiveData
public class MyLiveData extends MutableLiveData { @Override protected void onActive() { super.onActive(); Log.d("yink","onActive"); }@Override protected void onInactive() { super.onInactive(); Log.d("yink","onInactive"); } }

自定义LiveData的时候,跟我们其它继承用法一样。说下onActive和onInactive什么时候调用
  • onActive 两个条件:添加了observe + 生命周期alive。
  • onInactive 移除了observe,或者生命周期非alive。
    例:点击home到后台:onInactive; 重新进入页面:onActive ; 移除observe:onInactive
3.3、转换LiveData Livecycle给我提供了两种方法来转换LiveData
Transformations.map:把LiveData的值改变一下,目的是转换值
Transformations.switchMap:每次改变值时提供一个全新的liveData对象并监听这个新的liveData对象
下面我用相同的例子来讲解一下他们的区别,便于大家理解
我有一个MutableLiveData adressNumber; 来表示区号,然后我们要转换这个区号为当前哪个市区。于是有下面的代码
MutableLiveData adressNumber; MutableLiveData adressStringOne = (MutableLiveData) Transformations.map(adressNumber, new Function() { @Override public String apply(Integer input) { return getAdressString(input); } }); MutableLiveData adressStringTwo = (MutableLiveData) Transformations.switchMap(adressNumber, new Function() { @Override public LiveData apply(Integer input) { MutableLiveData mutableLiveData = https://www.it610.com/article/new MutableLiveData(); mutableLiveData.setValue(getAdressString(input)); return mutableLiveData; } }); private String getAdressString(Integer number) { if (number == 0755) return"深圳"; return "其它"; }

例子很简单,就是输入区号0755,查询出来是深圳。
map用法:
1、adressStringOne这个LiveData的值就是一个String,通过输入的0755来转换成”深圳“
2、adressStringOne对象没有变,每次监听adressNumber来设置自己的值
switchMap用法:
1、adressStringTwo这个LiveData同样拥有一个String值,通过输入的0755来转换成”深圳“
2、adressStringTwo和map用法不同的是,他拿到”深圳”这个值后,不是直接设置,而是new一个新的LiveData,adressStringTwo来监听LiveData变化并且和新的LiveData的值保持同步。
原理
原理也比较简单,贴出源码结合我上面的例子就很好理解了。
public interface Function { O apply(I input); }@MainThread public static LiveData map( @NonNull LiveData source, @NonNull final Function mapFunction) { final MediatorLiveData result = new MediatorLiveData<>(); result.addSource(source, new Observer() { @Override public void onChanged(@Nullable X x) { result.setValue(mapFunction.apply(x)); } }); return result; }

1、Function.apply只是方便我们自己去转换值
2、MediatorLiveData对象继承自MutableLiveData它提供的addSource方法可以观察LiveData对象,这也就是map和switchMap的关键实现。让LiveData可以观察LiveData
3、传入source,被观察者,它一变化就调用onChanged方法。在onChanged里MediatorLiveData设置新的值
4、流程简单总结就是:对象A来观察B的值,根据B的变化,A设置一个新的值,A观察B
@MainThread public static LiveData switchMap( @NonNull LiveData source, @NonNull final Function> switchMapFunction) { final MediatorLiveData result = new MediatorLiveData<>(); result.addSource(source, new Observer() { LiveData mSource; @Override public void onChanged(@Nullable X x) { LiveData newLiveData = https://www.it610.com/article/switchMapFunction.apply(x); if (mSource == newLiveData) { return; } if (mSource != null) { result.removeSource(mSource); } mSource = newLiveData; if (mSource != null) { result.addSource(mSource, new Observer() { @Override public void onChanged(@Nullable Y y) { result.setValue(y); } }); } } }); return result; }

1、Function.applyMediatorLiveData和上面map一个用法
2、当第一次x变化,进入onChanged,mSource = newLiveData,MediatorLiveData就会根据新的newLiveData来监听它的变化,addSource持值同步。
3、当第二次x变化,进入onChanged,mSource = newLiveData根据java局部变量特性,newLiveData是不同于第一次x变化时的newLiveData对象。此时会result.removeSource(mSource); 移除之前的监听,再重新监听这个新newLiveData的值,并且addSource保持值同步。
4、switchMapFunction的代码从头到尾,result.addSource了两次,也就是有两个监听
5、流程简单总结就是:A观察B的值,B变化必然创建一个新的C,A观察C。所以A同时观察B和C,只不过这个B每次变化会导致A监听一个新的C
6、当然如果你写switchMapFunction.apply(x); 实现的时候,返回的是同一个对象,那么C也不会变。
3.4、合并多个LiveData 合并多个LiveData目的很明确,比如一个按钮需要两个LiveData状态来确定, 你就需要同时监听两个LiveData才行。直接抛出一个例子,很简单就不详解了。
mediatorLiveData.addSource(addressNumber, new Observer() { @Override public void onChanged(Object o) { Address address = (Address)mediatorLiveData.getValue(); address.setNum((Integer)o); mediatorLiveData.setValue(address); } }); mediatorLiveData.addSource(addressString, new Observer() { @Override public void onChanged(Object o) { Address address = (Address)mediatorLiveData.getValue(); address.setString((String) o); mediatorLiveData.setValue(address); } }); mediatorLiveData.observe(this, new Observer() { @Override public void onChanged(Object o) {} }); class Address { Integer num; String string; ... }

四、写在最后 整体来看LiveData还是一个很简单的控件,它的核心思想 = Lifecycle + 观察者模式。优点离不开它的核心思想,简单来说生命周期有效性不用我们过多担心了,还有就是观察者模式的优点让我们刷新UI变的更便利,能给我们省去不少逻辑代码。所以它还是很巧妙的一个控件。

    推荐阅读