Android Jetpack架构组件-LiveData使用

谷歌推出的LiveData和RxJava类似,也是基于观察者,你可以认为LiveData是轻量级的RxJava。起初LiveData并不被看好,随着谷歌的大力推广,LiveData也慢慢的进入了大家的视野。一般来说,LiveData很少单独使用,它更多的和Android
Jetpack的其他组件搭配使用,比如和ViewModel、Room、Paging等。这篇文章就来介绍LiveData的使用。

一、定义

LiveData 是一种可观察的数据存储器类。与常规的可观察类不同,LiveData 具有生命周期感知能力,意指它遵循其他应用组件(如 Activity、Fragment 或 Service)的生命周期。这种感知能力可确保 LiveData 仅更新处于活跃生命周期状态的应用组件观察者。

二、优势:

使用 LiveData 具有以下优势:

  • 确保界面符合数据状态

    LiveData 遵循观察者模式。当生命周期状态发生变化时,LiveData 会通知 Observer 对象。您可以整合代码以在这些 Observer 对象中更新界面。观察者可以在每次发生更改时更新界面,而不是在每次应用数据发生更改时更新界面。

  • 不会发生内存泄露

    观察者会绑定到 Lifecycle 对象,并在其关联的生命周期遭到销毁后进行自我清理。

  • 不会因 Activity 停止而导致崩溃

    如果观察者的生命周期处于非活跃状态(如返回栈中的 Activity),则它不会接收任何 LiveData 事件。

  • 不再需要手动处理生命周期

    界面组件只是观察相关数据,不会停止或恢复观察。LiveData 将自动管理所有这些操作,因为它在观察时可以感知相关的生命周期状态变化。

  • 数据始终保持最新状态

    如果生命周期变为非活跃状态,它会在再次变为活跃状态时接收最新的数据。例如,曾经在后台的 Activity 会在返回前台后立即接收最新的数据。

  • 适当的配置更改

    如果由于配置更改(如设备旋转)而重新创建了 Activity 或 Fragment,它会立即接收最新的可用数据。

  • 共享资源

    您可以使用单一实例模式扩展 LiveData 对象以封装系统服务,以便在应用中共享它们。LiveData 对象连接到系统服务一次,然后需要相应资源的任何观察者只需观察 LiveData 对象,后文都会提高

三、使用liveData

LiveData的数据源一般是ViewModel,也可以是其它可以更新LiveData的组件。当数据更新后,LiveData 就会通知它的所有观察者,比如Activiy。

与RxJava的方法不同的是,LiveData并不是通知所有观察者,它只会通知处于Active状态的观察者,如果一个观察者处于Paused或Destroyed状态,它将不会收到通知。

这对于Activiy和Service特别有用,因为它们可以安全地观察LiveData对象而不用担心内存泄漏的问题。开发者也不需要在onPause或onDestroy方法中解除对LiveData的订阅。还有一点需要注意的是一旦观察者重新恢复Resumed状态,它将会重新收到LiveData的最新数据。

3.1、 LiveData的基本使用

示例为Button事件点击,LiveData发送个数据,观察者接收到数据更新以后更新UI

class LiveDataActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_live_data)

        var liveData: LiveData<String> = MutableLiveData<String>()

        btn_ald_post.setOnClickListener {
             //发送数据
            (liveData as MutableLiveData).postValue("有新消息了")
        }

      	//观察livedata对象
        liveData.observe(this, Observer<String> {
          	//Updata UI
            tv_ald_info.text = it
        })
    }
}

liveData.observe(this,Observer)方法有两个参数分别是LifecycleOwnerObserver ,第一个参数就是LiveDataActivity本身,因为父类已实现了LifecycleOwner接口,详情可参考笔者Lifecycle的文章,第二个参数则新建了一个Observer,在onChanged方法中得到回调。注释处的postValue方法会在主线程中更新数据,这样就会更改TextView中text属性的值。

在大多数情况下,LiveData的observe方法会放在onCreate方法中,如果放在onResume方法中,会出现多次调用的问题。除了MutableLiveData的postValue方法,还可以使用setValue方法,它们之前的区别是,setValue方法必须在主线程使用,如果是在工作线程中更新LiveData,则可以使用postValue方法。

3.2、 更改LiveData中的数据

如果我们想要在LiveData对象分发给观察者之前对其中存储的值进行更改,可以使用Transformations.map()Transformations.switchMap(),类似于Rxjava中的map()方法
下面通过简单的例子来讲解它们

        var liveData: LiveData<String> = MutableLiveData<String>()

        btn_ald_post.setOnClickListener {
            (liveData as MutableLiveData).postValue("有新消息了")
        }

        var changLiveData = Transformations.map(liveData) {
            it + "changed"
        }

        changLiveData.observe(this, Observer<String> {
            tv_ald_info.text = it
        })

运行结果为TextView的值为

"有新消息changed"

3.3、 Transformations.switchMap()

如果想要手动控制监听其中一个的数据变化,并能根据需要随时切换监听,这时可以使用Transformations.switchMap(),它和Transformations.map()使用方式类似,只不过switchMap()必须返回一个LiveData对象。

MediatorLiveDataLiveData 的子类,允许您合并多个 LiveData 源。只要任何原始的 LiveData 源对象发生更改,就会触发 MediatorLiveData 对象的观察者。

例如,如果界面中有可以从本地数据库或网络更新的 LiveData 对象,则可以向 MediatorLiveData 对象添加以下源:

  • 与存储在数据库中的数据关联的 LiveData 对象。
  • 与从网络访问的数据关联的 LiveData 对象。

    代码如下所示:
class MergerLiveDataActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_merger)
        
        val mutableLiveData1 = MutableLiveData<String>()
        val mutableLiveData2 = MutableLiveData<String>()
        val mutableLiveData3 = MutableLiveData<String>()
        val liveDataMerger: MediatorLiveData<*> = MediatorLiveData<String>()
        
        liveDataMerger.addSource(mutableLiveData1, object : Observer<String> {
            override fun onChanged(t: String?) {
                Log.d("TAG", "onChanged1:$t")
            }
        })

        liveDataMerger.addSource(mutableLiveData2, object : Observer<String> {
            override fun onChanged(t: String?) {
                Log.d("TAG", "onChanged2:$t")
            }
        })
        
        liveDataMerger.addSource(mutableLiveData3, object : Observer<String> {
            override fun onChanged(t: String?) {
                Log.d("TAG", "onChanged3:$t")
            }
        })
        
        liveDataMerger.observe(this, Observer {
            Log.d("TAG", "onChanged:$it");
        })
        

        mutableLiveData1.postValue("Onexzgj 的Jetpack")
        mutableLiveData2.postValue("Onexzgj 的Jetpack2")
        mutableLiveData3.postValue("Onexzgj 的Jetpack3")
    }
}

为了更直观的举例,将LiveData和MediatorLiveData放到了同一个Activity中。通过MediatorLiveData的addSource将两个MutableLiveData合并到一起,这样当任何一个MutableLiveData数据发生变化时,MediatorLiveData都可以感知到。

打印结果如下,任何一个liveData发生变化,liveDataMerger都会接受到通知
在这里插入图片描述

3.4、扩展LiveData对象

如果观察者的生命周期出于STARTED或者RESUMED状态,LiveData会将观察者视为处于Active状态,关于如何扩展LiveData,官网的例子比较简洁,如下所示:

    class StockLiveData(symbol: String) : LiveData<BigDecimal>() {
        private val stockManager = StockManager(symbol)

        private val listener = { price: BigDecimal ->
            value = price
        }

        override fun onActive() {
            stockManager.requestPriceUpdates(listener)
        }

        override fun onInactive() {
            stockManager.removeUpdates(listener)
        }
    }

上面的代码是一个观察股票变动的一个例子,对LiveData进行了拓展,实现了LiveData的两个空方法onActive和onInactive。当Active状态的观察者的数量从0变为1时会调用onActive方法,通俗来讲,就是当LiveData对象具有Active状态的观察者时调用onActive方法,应该在onActive方法中开始观察股票价格的更新。当LiveData对象没有任何Active状态的观察者时调用onInactive方法,在这个方法中,断开与StockManager服务的连接。

LiveData 对象具有生命周期感知能力,这一事实意味着您可以在多个 Activity、Fragment 和 Service 之间共享它们。为使示例保持简单,所以可以将 LiveData 类实现为单一实例,如下所示:

 class StockLiveData(symbol: String) : LiveData<BigDecimal>() {
        private val stockManager: StockManager = StockManager(symbol)

        private val listener = { price: BigDecimal ->
            value = price
        }

        override fun onActive() {
            stockManager.requestPriceUpdates(listener)
        }

        override fun onInactive() {
            stockManager.removeUpdates(listener)
        }

        companion object {
            private lateinit var sInstance: StockLiveData

            @MainThread
            fun get(symbol: String): StockLiveData {
                sInstance = if (::sInstance.isInitialized) sInstance else StockLiveData(symbol)
                return sInstance
            }
        }
    }

因此在Fragment中使用如下所示:

    class MyFragment : Fragment() {
        override fun onActivityCreated(savedInstanceState: Bundle?) {
            StockLiveData.get(symbol).observe(this, Observer<BigDecimal> { price: BigDecimal? ->
                // Update the UI.
            })
        }

多个 Fragment 和 Activity 可以观察 MyPriceListener 实例。仅当一个或多个系统服务可见且处于活跃状态时,LiveData 才会连接到该服务。

四、总结

这篇文章主要介绍了什么是LiveData,以及LiveData的使用方法,这里没有介绍LiveDataViewModel的结合使用,以及LiveData的原理,这些会在后面的文章进行介绍。

最后文章中涉及到的源码及Jetpack的全组件均上传至OnexZgj/Jetpack_Component

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