Android Jetpack系列组件之:LiveData(保姆级教程)
Android Jetpack系列组件之:LiveData(保姆级教程)
提示:建议新手多查阅官网资料,官网文档永远是第一手学习资料
官网链接:https://developer.android.com/topic/libraries/architecture/livedata?hl=zh-cn
LiveDate 保姆教程
- Android Jetpack系列组件之:LiveData(保姆级教程)
- @[TOC](LiveDate 保姆教程)
- 前言
- 一、LiveData 的优势
- 1.确保界面符合数据状态
- 2.避免发生内存泄漏
- 3.不会因Activity停止而出现Crash问题
- 4.不需要手动处理生命周期
- 5.数据始终保持最新状态
- 6.共享资源
- 二、如何使用LiveData对象
- 使用说明
- 三、应用架构中的LiveData
- 四、扩展LiveData
- 单例模式
- 五、转换LiveData
LiveDate 保姆教程
- Android Jetpack系列组件之:LiveData(保姆级教程)
- @[TOC](LiveDate 保姆教程)
- 前言
- 一、LiveData 的优势
- 1.确保界面符合数据状态
- 2.避免发生内存泄漏
- 3.不会因Activity停止而出现Crash问题
- 4.不需要手动处理生命周期
- 5.数据始终保持最新状态
- 6.共享资源
- 二、如何使用LiveData对象
- 使用说明
- 三、应用架构中的LiveData
- 四、扩展LiveData
- 单例模式
- 五、转换LiveData
前言
什么是LiveData:及一种可观察的数据存储器类,LiveData具有生命周期感知能力,遵循其他应用组件(如activity、fragment或service)的生命周期
官网的概念进行如下解释:这个LiveData既是一个可以装数据的存储器,也是一个同四大组件的生命周期相互绑定的数据存储组件
一、LiveData 的优势
1.确保界面符合数据状态
LiveData遵循观察者模式,当底层数据发生变化时,LiveData会通知Observe对象,进而去Observe对象中更新UI操作,方便了开发者持续去监听数据的更新状态而更新UI
2.避免发生内存泄漏
观察者会绑定到LifeCycle对象,并关联其生命周期,随多绑定的对象的生命周期的销毁而进行自我清理
3.不会因Activity停止而出现Crash问题
如果观察者的生命周期处于非活跃状态(例如在返回堆栈中的Activity),它便不会接受任何LiveData时间
4.不需要手动处理生命周期
界面组件只是观察相关数据,不会停止或恢复观察,LiveData将自动管理所有这些操作,其在观察时可以感知相关的生命周期的状态变化(同第二条,与LifeCycle对象相绑定,关联其生命周期)
5.数据始终保持最新状态
如果生命周期变为非活跃状态,它会在再次变为活跃状态时接受最新的数据(如曾经在后台的Activity会在返回前台后立刻接受最新的数据)
6.共享资源
可以利用单例模式,扩展LiveData对象以封装相关系统服务,以便在应用中共享它们,LiveData对象连接到系统服务一次,然后需要相应资源的任何观察者只需观察LiveData对象。(之后具体举例说明)
二、如何使用LiveData对象
使用说明
在ViewModel中:创建LiveData的实例,用来存储某种数据类型的数据
在Activity或fragment中:使用onChange() 或 observer() 方法,创建observer对象,用于观察当LiveData对象存储的数据发生变化时界面上的相应处理(更新UI等操作)
大多数情况下,应用组件的onCreate() 方法 是开始观察 LiveData 对象的正确着手点
可以使用 observeForever(Observer) 方法 在没有关联的 LifecycleOwner 对象的情况下注册一个观察者。这种情况下,观察者始终处于活跃状态,因此始终可以收到关于修改的通知,手动调用 removeObserve(Observer) 方法 来移除这些观察者
//ViewModel 层 创建LiveData
class MyViewModel : ViewModel() {//实例化 LiveDataval myLiveData : MutableLiveData<String> by lazy {MutableLiveData<String>()}
}//应用组件层 使用&&更新 LiveData
class MyActivity : AppCompatActivity() {private val myViewModel : MyViewModel by viewModels()override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)//开始观察LiveDataval myLiveDataObserver = Observer<String> { liveDate ->//取数据 用于更新页面UImyTextView.text = liveDate }//观察 LiveDatamyViewModel.myLiveData.observe(this, myLiveDataObserver)}//更新LiveData的数据private fun updateLiveData() {//比如UI层的点击实现,相应更新LiveData的操作...button.setOnClickLister {val changeData = "change Data"myViewModel.myLiveData.setValue(changeData)//在非主线程使用 postValue() }}
}
拓展思路(后续专栏详解):
- 将LiveData与Room一起使用
- 将协程与LiveData一起使用
三、应用架构中的LiveData
在架构层使用LiveData与其他组件间的使用规则:
- LiveData具有生命周期感知能力,遵循Activity 和 Fragment 等实体的生命周期,使用LiveData 在这些生命周期所有者和生命周期不同的其他对象(如ViewModel对象)之间传递数据
- ViewMode主要负责加载和管理与界面相关的数据,非常适合用于保留LiveData对象,及在ViewModel中创建LiveData对象,并向界面层公开出去
- 在数据层类中使用LiveData,但注意LiveData不适用于处理异步数据流
- LiveData与Kotlin Flow的组合使用
//在 Repository 中保留 LiveData 阻塞主线程
class MyRepository {fun getUser(): LiveData<List<User>> {...}fun getNewPrimiumUsers(): LiveData<List<User>> {return getUser().map { users ->users.filter { user ->user.isPremium}.filter { user ->val lastSyncedTime = dao.getLastSyncedTime()user.timeCreated > lastSyncedTime}}}}
四、扩展LiveData
若观察者的生命周期处于Started或者Resumed状态,LiveData会认为该观察者处于活跃状态
class MyLiveData(symbol: String) : LiveData<BigDecimal>() {private val dataManager = DataManager(symbol)private val listener = { price: BigDecimal ->value = price}//当LiveData 对象具有活跃观察者时,会调用onActive() 方法override fun onActive() {dataManager.requestPriceUpdates(listener)}//当LiveData 对象没有任何活跃观察者时,会调用onInactive() 方法override fun onInactive() {dataManager.removeUpdates(listener)}
}//使用MyLiveData类
public class MyFragment : Fragment() {override fun onViewCreated(view: View, savedInstanceState: Bundle?) {super.onViewCreated(view, savedInstanceState)val myPriceListener: LiveData<BigDecimal> = ...myPriceListener.observe(viewLifecycleOwner, Observer<BigDecimal> { price: BigDecimal? ->//update the UI}) }
}
单例模式
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@MainThreadfun get(symbol: String): StockLiveData {sInstance = if (::sInstance.isInitialized) sInstance else StockLiveData(symbol)return sInstance}}
}//在Fragment中使用
class MyFragment : Fragment() {override fun onViewCreated(view: View, savedInstanceState: Bundle?) {super.onViewCreated(view, savedInstanceState)StockLiveData.get(symbol).observe(viewLifecycleOwner, Observer<BigDecimal> { price: BigDecimal? ->// Update the UI.})}
- 多个 fragment 和 activity 可以观察 MyPriceListener 实例。仅当一个或多项系统服务可见且处于活跃状态时,LiveData 才会连接到该服务。
五、转换LiveData
需求场景:希望将LiveData 对象分配给观察者之前对存储在其中的值进行更改,或者需要根据另一个实例的值返回不同的LiveData实例,Lifecycle提供Transfromations类来进行相关处理
//对存储在LiveData对象中的值应用函数 并将该结果传播到下游
val userLiveData: LiveData<User> = UserLiveData()
val userName: LiveData<Strring> = userLiveData.map {user-> "${user,name} ${user.lastName}"
}//与map类似,将存储在LiveData对象中的值应用函数,并将结果解封和分派到下游,传递给switchMap()的函数必须返回LiveData对象
private fun getUser(id: String): LiveData<User> {...
}
val userId: LiveData<Strng> = ...
val user = userId.switchMap { id-> getUser(id) }