初探Architecture Components之LiveData

版权声明:本文为博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/IO_Field/article/details/75301954

Demo地址: Kotlin-Dagger-2-Retrofit-Android-Architecture-Components

初探Architecture Components之Lifecycle中,我们已经了解到Lifecycle是如何与组件的生命周期相关联的。在本文中,我们将会了解Architecture Components库如何管理数据,那就是LiveData?LiveData是一个持有数据的类,并将数据作为其值,并允许监测它(用了观察者模式)。与常规的观察者模式不同,LiveData与组件的生命周期, 以便Observer在指定的生命周期内观察数值的变化。

不管LiveData是与组件的生命周期相关联,还是其采用观察者模式检测数值的变化,它有什么吸引力让我们使用它呢?

  • 避免内存泄漏: 由于Observers绑定本身的Lifecycle对象, 当Lifecycle被销毁时, 其自动被移除。
  • Activity处于onstop状态时, 不会导致应用程序意外崩溃: 当观察者的的生命周期处于非活动状态(比如Activity处于后台堆栈)时, Observer不会接到数据的变化
  • 收到更改事件
  • 始终保持最新的数据: 当Lifecycle再次回到可活动状态时(比如Activity从后台堆栈返回到前台), 它会受到最新的更改信息
  • 适当的配置更改: 如果由于配置更改(比如设置旋转)重新创建Activity/Fragment时, 会立即接收到最有可用的数据。
  • 共享资源: 可用保留一个有用的实例, 分享给多个Activity或者Fragment
  • 没有针对生命周期做出多余的针对处理: 一切生命周期的变化, 所造成的的处理事务, 由LiveData自动管理。

这里有两个疑问,LiveData是如何始终保持最新的数据呢?如果在后台获取到数据,Observe是在什么时候接收到数据盘的呢?带着这两个疑问接着往下看…

在LiveData中,有4个重要的方法:

  • onActive(): 当LiveData有可观察的对象时回调
  • onInactive(): 当LiveData没有可观察的对象时回调
  • setValue(): 当LiveData更新实例的值时调用, 并通知Observer数据的更改
  • postValue: 当LiveData更新实例的值时调用, 并通知Observer数据的更改

其中,setValue和postValue方法都是用来LiveData更新实例时调用。值得注意的是,setValue方法只能在主线程中调用,而postValue可以在任何线程中调用。也就是说,如果是在后台子线程中更新LiveData的值,必须调用postValue。

class PersonActivity : LifecycleActivity(), LifecycleRegistryOwner {

    ***

    override fun onCreate(savedInstanceState: Bundle?) {

        ***

        Log.i("tea", " onCreate")

        personLiveData.observe(this, Observer<Person?> {
            Log.d("tea", "id: ${it?.id} | name: ${it?.name}")
            tvValue.text = "id: ${it?.id} | name: ${it?.name}"
        })

        setListener()
    }

    private fun setListener() {
        btnSet.setOnClickListener {
            personLiveData.value = Person(1, "SetValue")
        }

        btnPost.setOnClickListener {
            doAsync {
                personLiveData.postValue(Person(1, "PostValue"))
            }
        }
    }

    override fun onStop() {
        super.onStop()
        personLiveData.value = Person(3, "onStop")
        Log.i("tea", " onStop")
    }
}


class PersonLiveData : LiveData<Person>() {

    override fun onActive() {
        super.onActive()
        Log.d("tea", "onActive")
    }

    override fun onInactive() {
        super.onInactive()
        Log.d("tea", "onInactive")
    }

    public override fun postValue(value: Person?) {
        super.postValue(value)
    }

    public override fun setValue(value: Person?) {
        super.setValue(value)
    }
}

由于LiveData是一个抽象类,无法创建创建实例。现创建LiveData的子类PersonLiveData,PersonActivity中创建了PersonLiveData实例。值得注意的是, observe()方法的第一个参数为LifecycleOwner, 表示Observer应当绑定Lifecycle, 这样意味着:

  • Lifecycle未处于STARTED或RESUMED状态, 即使该值发生了变化, Observer不会被通知。
  • 如果Lifecycle被杀掉, Observer将被自动清除。

在onStop方法里我们通过setValue方法更改了personLiveData中数据的值,我们来看看Observer是什么时候接收到的数值变化的通知呢?
从下图中,我们可以清晰的看到:Observe并没有在personLiveData中数据值发生变化时立即受到通知,而是在PersonActivity重新可见时,Observe才接收到数值变化的通知。关于这样的优点,这里不必多说,前面已有介绍。

在下图中,我们可以还可以看到组件的生命周期、LiveData和Lifecycle等相关方法的调用顺序:

这里写图片描述

LiveData与组件的生命周期相关联, 意味着我们可以在多个Activity或者Fragment中共用它。 前面我们是在Activity中使用它,我们一样在Fragment中使用:

public class MyFragment: LifecycleFragment() {
    fun onActivityCreated (Bundle savedInstanceState) {
         personLiveData.observe(this, Observer<Person?> {
                Log.d("tea", "id: ${it?.id} | name: ${it?.name}")
                tvValue.text = "id: ${it?.id} | name: ${it?.name}"
            })
    }
}

LiveData的转换

有时候,在将数据变化信息发送给Observer之前,需要对LiveData值的数据类型进行更改(这里说的不是值本身的变化,而是数据类型的变化),此时,就需要需要依据当前LiveData,返回另外一个LiveData实例。我们该怎么做呢?是在Observe回调里面重新创建一个LiveData还是?

在android.arch.lifecycle包提供了Transformations工具类, 用于LieveData值的数据类型的更改。在Transformations类中有两个方法map()和switchMap.

map

先看map方法,它接受两个参数:一个LiveData作为数据源和一个转换函数Function。其中,传递的转换函数应在主线程中执行,因为该函数用于数据源LiveData发出的每个值,并返回发出结果值的LiveData。

现在我们将personLiveData的值的数据类型转换String类型:

var personMapLiveData: LiveData<String>
personMapLiveData = Transformations.map(personLiveData, {
    it: Person? ->

    it?.name
})

personMapLiveData.observe(this, Observer<String> {
    tvMap.text = it
})

switchMap

现在我们看看switchMap,与map类似,将LiveData的值更改信息传递给子LiveData,不同的是,传递给它的函数必须返回一个LiveData对象。这就意味着,这种实现可能从将原来的LiveData销毁,并且在数据源LiveData数值发生变化时,重新创建一个新的LiveData实例。

var personSwitchMapLiveData: LiveData<String>
personSwitchMapLiveData = Transformations.switchMap(personLiveData) {
    val result = MediatorLiveData<String>()
    it.name
    result.postValue(it.name)
    result
}

personSwitchMapLiveData.observe(this, Observer<String> {
    tvSwitchMap.text = it
})

自定义LiveData

前面提到了LiveData的重要方法中包括setValue和postValue,值得注意的是这两个方法使用protected修饰,这意味着它们只能在LiveData的子类中调用。又由于,LiveData是一个抽象类,我们并不能创建其相应的实例。如果我们想创建其实例,不得不自定义LiveData的子类,比如,前面定义的PersonLiveData。在android.arch.lifecycle包中,有LiveData的两个实现类:MutableLiveData和MediatorLiveData。

MutableLiveData继承自LiveData,其主要是对外公布了setValue和postValue(注意方法的调用时所属线程)。

public class MutableLiveData<T> extends LiveData<T> {
    @Override
    public void postValue(T value) {
        super.postValue(value);
    }

    @Override
    public void setValue(T value) {
        super.setValue(value);
    }
}

而,MediatorLiveData又继承自MutableLiveData类,也就是说该类也公开了setValue和postValue方法。该类该又增加了监测其他LiveData实例值个更改并处理它们发出的事件。

  • addSource(LiveData<S> source, Observer<S> onChanged):添加监控的LiveData实例值及LiveData的值变化时处理的Observe
  • removeSource(LiveData<S> toRemote):移除监控的LiveData实例值

如果你兴趣可以根据自己的需求自定义LiveData,比如前面的PersonLiveData。

展开阅读全文

没有更多推荐了,返回首页