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
- 在 ViewModel 中定义 LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModelclass NameViewModel : ViewModel() {val currentName: MutableLiveData<String> by lazy {MutableLiveData<String>()}
}
- 使用 LiveData 的 observe 方法
import androidx.lifecycle.ViewModelProviderviewModel = ViewModelProvider(this)[NameViewModel::class.java]
viewModel?.currentName?.observe(this, { name -> textView.text = name })
observe 方法有两个参数
- 第一个是 LifecycleOwner 对象。这样 LiveData 就会感知 LifecycleOwner 的生命周期,只在 LifecycleOwner 活跃的时候才去调用第二个参数的 onChanged 方法
- 第二个参数是 Observer 对象。Observer 是一个 interface,它的 onChanged 会在 LiveData 更新的时候被调用
- 更新 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.LiveDataclass NetworkLiveData(private val context: Context?) : LiveData<NetworkInfo?>() {private var networkReceiver: NetworkReceiverprivate var intentFilter: IntentFilterinit {networkReceiver = NetworkReceiver()intentFilter = IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION)}companion object {private lateinit var instance: NetworkLiveData@MainThreadfun 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? ConnectivityManagerval networkInfo = connectivityManager?.activeNetworkInfogetInstance(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 LiveData 源码解析
是什么 LiveData 是具备生命周期的数据,当数据放生变化的时候,如果页面已经销毁,那么就不会回调给监听者. 有什么用? 当我们获取到网络请求的数据,如果页面已经销毁了,就不会调用更新Ui 的方法 ...
- Android Jetpack组件之 LiveData使用-源码
1.前言 最近简单看了下google推出的框架Jetpack,感觉此框架的内容可以对平时的开发有很大的帮助,也可以解决很多开发中的问题,对代码的逻辑和UI界面实现深层解耦,打造数据驱动型UI界面. A ...
- Android Jetpack之DataBinding+ViewModel+LiveData+Room
Android Jetpack之ViewModel.LiveData Android Jetpack之LifeCycle 前言 Jetpack是一个由多个技术库组成的套件,可帮助开发者遵循最佳做法,减 ...
- Android Jetpack Components of LiveData 学习笔记
Android Jetpack Components of Lifecycle 学习笔记 Android Jetpack Components of LiveData 学习笔记 Android Jet ...
- Android Jetpack架构组件之 Room(使用、源码篇)
2019独角兽企业重金招聘Python工程师标准>>> 1.前言 最近简单看了下google推出的框架Jetpack,感觉此框架的内容可以对平时的开发有很大的帮助,也可以解决很多开发 ...
- Android Jetpack组件之Hilt使用
前言 最近简单看了下google推出的框架Jetpack,感觉此框架的内容可以对平时的开发有很大的帮助,也可以解决很多开发中的问题,对代码的逻辑和UI界面实现深层解耦,打造数据驱动型UI界面. And ...
- Android Jetpack组件App Startup简析
1.前言 最近简单看了下google推出的框架Jetpack,感觉此框架的内容可以对平时的开发有很大的帮助,也可以解决很多开发中的问题,对代码的逻辑和UI界面实现深层解耦,打造数据驱动型UI界面. A ...
- Android Jetpack组件之WorkManger使用介绍
1.前言 最近简单看了下google推出的框架Jetpack,感觉此框架的内容可以对平时的开发有很大的帮助,也可以解决很多开发中的问题,对代码的逻辑和UI界面实现深层解耦,打造数据驱动型UI界面. A ...
- Android Jetpack组件之Navigation使用-源码
1.前言 最近简单看了下google推出的框架Jetpack,感觉此框架的内容可以对平时的开发有很大的帮助,也可以解决很多开发中的问题,对代码的逻辑和UI界面实现深层解耦,打造数据驱动型UI界面. A ...
最新文章
- Android 第三方之MPAndroidChart
- 千万级、百万级数据删除优化
- [沪江日语电台]ACG杂货铺02-乱唱地带
- 数据挖掘中聚类算法概述
- 软件测试岗需要会什么条件,应聘软件测试岗位需要具备什么条件?
- μC/OS-III---I笔记3---时间管理
- python输入数据的维度_python – Keras LSTM输入维度设置
- 【错误】expected constructor, destructor, or type conversion before '.' token - 第八个游侠的日志 - 网易博客...
- 微信公众号全局返回码
- Bresenham直线插补算法
- [算法导论] 邮递员问题
- 从 SEC EDGAR 获取股东治理数据 (Shareholder Activism)
- 全球四大卫星导航系统年鉴
- (JAVA) 相邻数对
- 至联云课堂:隐私泄露屡禁不止,根本原因其实是...
- 数据集:人群行为识别数据库总结
- 杭州计算机职称考试培训,杭州全国职称英语等级考试强化培训班(综合类)
- 电子和计算机工程密歇根大学,美国密歇根大学迪尔本校区电子与计算机工程系主任 Yi Lu Murphey教授来我校进行学术交流并作学术报告...
- c语言冒泡排序法6,C语言的冒泡排序法
- [Android学习] 1. 简易登录界面设计
热门文章
- Maven-将jar包发布到本地maven仓库与私服
- 怎么让段落自动空两格_word自动空两格 如何设置word中段首自动空两格
- 【IPAVS】AV多媒体管理控制中心,AV媒体矩阵
- Jsp医院病区管理系统(论文+中期检查表+任务书+综合材料)
- SegNet: A Deep Convolutional Encoder-Decoder Architecture for Image Segmentation
- Yann LeCun主讲,纽约大学《深度学习》2021春季课程放出,免费可看
- 计算机主要键符的功能怎么读,计算机键盘中的全部按键基本功能.doc
- 电脑常用快捷键大全(含Visual Studio快捷键操作)
- word标题突然变成黑方框???
- 怎么把xml文件到url post方法 android,如何在android中使用http post发送xml文件.我把xml文件放在代码中...