Android Jetpack - LiveData

Posted teletian

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android Jetpack - LiveData相关的知识,希望对你有一定的参考价值。

◾︎简介

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

这是官网上的一段话。意思就是 LiveData 的更新能够被 LifecycleOwner 所感知,但是前提是 LifecycleOwner 处于活跃状态。这样就有效的避免了更新 UI 时 Activity 已经不处于活跃而导致的崩溃。

本文代码使用 Kotlin 讲解,若需查看 Java 代码写法,请参考文末 Sample

◾︎添加依赖

LiveData 一般和 ViewModel 一起使用。

def lifecycle_version = "2.3.1"

// ViewModel
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycle_version"
// LiveData
implementation "androidx.lifecycle:lifecycle-livedata-ktx:$lifecycle_version"

◾︎使用

应当避免将 LiveData 直接存储在 Activity / Fragment 中,因为 Activity / Fragment 只负责 UI 显示,而不负责数据存储。

简单的使用 LiveData

  1. 在 ViewModel 中定义 LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel

class NameViewModel : ViewModel() {

    val currentName: MutableLiveData<String> by lazy {
        MutableLiveData<String>()
    }
}
  1. 使用 LiveData 的 observe 方法
import androidx.lifecycle.ViewModelProvider

viewModel = ViewModelProvider(this)[NameViewModel::class.java]
viewModel?.currentName?.observe(this, { name -> textView.text = name })

observe 方法有两个参数

  • 第一个是 LifecycleOwner 对象。这样 LiveData 就会感知 LifecycleOwner 的生命周期,只在 LifecycleOwner 活跃的时候才去调用第二个参数的 onChanged 方法
  • 第二个参数是 Observer 对象。Observer 是一个 interface,它的 onChanged 会在 LiveData 更新的时候被调用
  1. 更新 LiveData
viewModel?.currentName?.value = "更新 LiveData"

更新 LiveData 有两种方法

  • setValue。在主线程时使用 setValue
  • postValue。在子线程时使用 postValue,其实内部就是使用了 Handler 把值 post 到主线程去了。如果在主线程执行之前调用了多次 postValue,只有最后一次有效

LiveData vs MutableLiveData

LiveData 的 setValue 和 postValue 是 protected 的,只能在 ViewModel 内部使用。MutableLiveData 的 setValue 和 postValue 是 public 的,可以在任何地方使用。

自定义 LiveData

自定义一个监听网络状态的 LiveData

import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.net.ConnectivityManager
import android.net.NetworkInfo
import android.util.Log
import androidx.annotation.MainThread
import androidx.lifecycle.LiveData

class NetworkLiveData(private val context: Context?) : LiveData<NetworkInfo?>() {

    private var networkReceiver: NetworkReceiver
    private var intentFilter: IntentFilter

    init {
        networkReceiver = NetworkReceiver()
        intentFilter = IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION)
    }

    companion object {
        private lateinit var instance: NetworkLiveData

        @MainThread
        fun getInstance(context: Context?): NetworkLiveData {
            instance = if (::instance.isInitialized) instance else NetworkLiveData(context)
            return instance
        }
    }

    override fun onActive() {
        super.onActive()
        Log.d("tianjf", "onActive")
        context!!.applicationContext.registerReceiver(networkReceiver, intentFilter)
    }

    override fun onInactive() {
        super.onInactive()
        Log.d("tianjf", "onInactive")
        context!!.applicationContext.unregisterReceiver(networkReceiver)
    }

    inner class NetworkReceiver : BroadcastReceiver() {
        override fun onReceive(context: Context?, intent: Intent?) {
            val connectivityManager =
                context?.getSystemService(Context.CONNECTIVITY_SERVICE) as? ConnectivityManager
            val networkInfo = connectivityManager?.activeNetworkInfo
            getInstance(context).value = networkInfo
        }

    }
}

自定义 LiveData 会覆写 onActive 和 onInactive 方法。它们会监听 LifecyclerOwner 的生命周期。当进入活跃状态(STARTED 或者 RESUMED)时,调用 onActive 方法,当进入非活跃状态时,调用 onInactive 方法。
在 onActivie 中注册广播,在 onInactive 中注销广播。这样代码就非常清晰明了了,网络状态的处理和 Activity/Fragment 分离开了。

转换 LiveData

转换会用到 Translations.map 和 Translations.switchMap
map、switchMap 和 RxJava 中的 map、flatMap 类似

Translations.map
val userLiveData: LiveData<User> = UserLiveData()
val userName: LiveData<String> = Transformations.map(userLiveData) {
    user -> "${user.name} ${user.lastName}"
}

当更新 userLiveData 的值时,会自动触发 userName 的 setValue 操作。其实就是对数据做 map 操作,转换为需要的格式。

Translations.switchMap
private fun getUser(id: String): LiveData<User> {
  ...
}
val userId: LiveData<String> = ...
val user = Transformations.switchMap(userId) { id -> getUser(id) }

当设置 userId 的时候,会自动触发 getUser 操作并返回另一个 LiveData

MediatorLiveData

map 和 switchMap 的源码中都使用到了 MediatorLiveData。
从名称可以看出,MediatorLiveData 使用了终结者模式。
MediatorLiveData 可以接管普通的 LiveData,使得当 LiveData 有数据更新的时候,MediatorLiveData 也能够 “收到响应”。

private val originData = MutableLiveData<String>()
private val mediatorLiveData = MediatorLiveData<String>()

mediatorLiveData.addSource(originData) { Log.i("tianjf", "originData: $it") }

MediatorLiveData 可以添加多个 LiveData

private val originData1 = MutableLiveData<String>()
private val originData2 = MutableLiveData<String>()
private val mediatorLiveData = MediatorLiveData<String>()

mediatorLiveData.addSource(originData1) { mediatorLiveData.value = "originData: $it" }
mediatorLiveData.addSource(originData2) { mediatorLiveData.value = "originData: $it" }

observe 和 observeForever

observeForever 和 observe 的区别是,LifecyclerOwner 在非活跃状态下也会调用 Observer 的 onChanged 方法。
为了防止内存泄露,必须手动调用 removeObserver 方法

◾︎Sample

Kotlin 版
Java 版

以上是关于Android Jetpack - LiveData的主要内容,如果未能解决你的问题,请参考以下文章

Android Jetpack架构组件带你了解Android Jetpack

Android Jetpack简介

Android Jetpack架构组件——什么是Jetpack?

Android Jetpack架构组件——什么是Jetpack?

《Android Jetpack从入门到精通+高级Jetpack强化实战》,最新Jetpack系列开发笔记开源

Android高级Jetpack架构组件+Jetpack compose强化实战