Android Jetpack解析之——LiveData_什么生命周期下开始observelivedata

最后

最后为了帮助大家深刻理解Android相关知识点的原理以及面试相关知识,这里放上相关的我搜集整理的24套腾讯、字节跳动、阿里、百度2019-2021BAT 面试真题解析,我把大厂面试中常被问到的技术点整理成了视频和PDF(实际上比预期多花了不少精力),包知识脉络 + 诸多细节。

还有 高级架构技术进阶脑图 帮助大家学习提升进阶,也节省大家在网上搜索资料的时间来学习,也可以分享给身边好友一起学习。

Android 基础知识点

Java 基础知识点

Android 源码相关分析

常见的一些原理性问题

希望大家在今年一切顺利,进到自己想进的公司,共勉!

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化学习资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

    // Observe the LiveData, passing in this activity as the LifecycleOwner and the observer.
    model.currentName.observe(this, nameObserver)
}

}


在传递nameObserver参数的情况下调用observer()后,系统会立即调用onChanged(),从而提供mCurrentName中存储的最新值。如果LiveData对象尚未在mCurrentName中设置值,系统不会调用onChanged()。


### 2.3、更新LiveData对象


LiveData没有公开可用的方法来更新存储的数据。MutableLiveData类将公开setValue(T)和postValue(T)方法,如果您需要修改存储在LiveData对象中的值,则必须使用这些方法。通常情况下只会在ViewModel中使用MutableLiveData,然后ViewModel只会向观察者公开不可变的LiveData对象。


设置观察者关系后,您可以更新LiveData对象的值(如以下示例中所示),这样当用户点按某个按钮时会触发所有观察者:



button.setOnClickListener {
val anotherName = “John Doe”
model.currentName.setValue(anotherName)
}


在本示例中调用setValue(T)导致观察者使用值John Doe调用其onChanged()方法。本示例中演示的是按下按钮的方法,但也可以出于各种各样的原因调用setValue()或postValue()来更新mName,这些原因包括相应网络请求或数据库加载完成。在所有情况下,调用setValue()或postValue()都会触发观察者并更新界面。



注意:您必须调用setValue(T)方法一以从主线程更新LiveData对象。如果在工作器线程中执行,您可以改用postValue(T)方法来更新LiveData对象。


#### 2.4、将LiveData与Room一起使用


Room持久性库支持返回LiveData对象的可观察查询。可观察查询属于数据库访问对象(DAO)的一部分。


当数据库更新时,Room会生成更新LiveData对象所需的所有代码。早需要时,生成的代码会在后台线程上异步运行查询。此模式有助于使界面中显示的数据与存储在数据库中的数据保持同步。


### 3、应用架构中的LiveData


LiveData具有生命周期感知能力,遵循activity和fragment等实体的生命周期。您可以使用LiveData在这些声明周期所有者和声明周期不同的其他对象(例如ViewModel对象)之间传递数据。ViewModel的主要责任是加载和管理与界面相关的数据,因此非常适合作用于保留LiveData对象的备选方案。您可以在ViewModel中创建LiveData对象,然后使用这些对象向界面层公开状态。


activity和fragment不应保留LiveData实例,因为它们的用途是显示数据,而不是保持状态。此外,如果activity和fragment无需保留数据,还可以简化单元测试的编写。


您可能会想在数据层类中使用LiveData对象,但LiveData并不适合用于处理异步数据流。虽然您可以使用LiveData转换和MediatorLiveData来实现此目的,但此方法的缺点在于:用于组合数据流的功能非常有限,并且所有LiveData对象(包括通过转换创建的对象)都会在主线程中观察到。下方是一段示例代码,展示了在Respository中保留LiveData如何阻塞主线程:



class UserRepository {
// DON’T DO THIS! LiveData objects should not live in the repository
fun getUsers(): LiveData<List> {

}

fun getNewPremiumUsers(): LiveData<List<User>> {
    return getUsers().map { user ->
        // This is an expensive call being made on the main thread and may
        // cause noticeable jank in the UI!
        users
            .filter { user ->
                user.isPermium
            }
        .filter { user ->
            val lastSyncedTime = dao.getLastSyncedTime()
            user.timeCreated > lastSyncedTime
        }
    }
}

}


如果您需要在应用的其他层中使用数据流,请考虑使用Kotlin Flow,然后使用asLiveData()在ViewModel中将Kotlin Flow转换成LiveData。


### 4、扩展LiveData


如果观察者的额生命周期处于STARTED或RESUMED状态,LiveData会认为观察者处于活跃状态。以下示例代码说明了如何扩展LiveData类:



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

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

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

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

}


本示例中的价格监听器实现包括以下重要方法:


* 当LiveData对象具有活跃观察者时,会调用onActive()方法。这意味着,您需要从此方法开始观察股价更新。
* 当LiveData对象没有任何活跃观察者时,会调用onInactive()方法。由于没有观察者在监听,因此没有理由与StockManager服务保持连接。
* setValue(T)方法将更新LiveData示例的值,并将更改告知活跃观察者。


您可以使用StockLiveData类,如下所示:



public class MyFragment: Fragment() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val myPriceListener: LiveData = …
myPriceListener.observe(viewLifecycleOwner, Observer { price: BigDecimal? ->
// Update the UI
})
}
}


observe()方法将与Fragment视图关联的LifecycleOwner作为第一个参数传递。这样做表示此观察者已绑定到与所有者关联的Lifecycle对象,这意味着:


* 如果Lifecycle对象未处于活跃状态,那么即使值发生更改,也不会调用观察者。
* 销毁Lifecycle对象后,会自动移除观察者。


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



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

private val listener = { prive: 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 onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
StockLiveData.get(symbol).observe(viewLifecycleOwner, Observer { price: BigDecimal? ->
// Update the UI
}
}


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


### 5、转换LiveData


您可能希望在将LiveData对象分派给观察者之前对存储在其中的值进行更改,或者您可能需要根据另一个实例的值返回不同的LiveData实例。Lifecycle软件包会提供Transformations类,该类包括可应对这些情况的辅助程序方法。


Transformations.map()  
 :对存储在LiveData对象中的值应用函数,并将结果传到下游。



val userLiveData: LiveData = UserLiveData()
val userName: LiveData = userLiveData.map {
user -> “${user.name} ${user.lastName}”
}


Transformations.switchMap()  
 :与map()类似,对存储在LiveData对象中的值应用函数,并将结果解封和分派到下游。传递给switchMap()的函数必须返回LiveData对象,如以下示例中所示:



private fun getUser(id: String): LiveData {

}
val userId: LiveData = …
val user = userId.switchMap { id -> getUser(id) }


您可以使用转换方法在观察者的生命周期内传送信息。除非观察者正在观察返回的LiveData对象,否则不会计算转换。因为转换时以延迟的方式计算,所以与生命周期相关的行为会隐式传递下去,而不需要额外的显示调用或依赖项。


如果您认为ViewModel对象中需要有Lifecycle对象,那么进行转换或许是更好的解决方案。例如,假设您有一个界面组件,该组件接受地址并返回该地址的邮政编码。您可以为此组件实现简单的ViewModel,如以下示例代码所示:



class MyViewModel(private val repository: PostalCodeRepository): ViewModel() {
private fun getPostalCode(address: String): LiveData {
// DON’T DO THIS
return repository.getPostCode(addredd)
}
}


然后,该界面组件需要取消注册先前的LiveData对象,并在每次调用getPostalCode()时注册到新的实例。此外,如果重新创建了该界面组件,它会再出发一次对repository.getPostCode()方法的调用,而不是使用先前调用所得的结果。


您也可以将邮政编码查询实现为地址输入的转换,如以下示例中所示:



class MyViewModel(private val repository: PostalCodeRepository): ViewModel() {
private val addressInput = MutableLiveData()
val postalCode: LiveData = addressInput.switchMap{ address -> repository.getPostCode(address) }

private fun setInput(address: String) {
    addressInput.value = address
}

}


在这种情况下,postalCode字段定义为addressInput的转换。只要您的应用具有与postalCode字段关联的活跃观察者,就会在每次addressInput发生更改时重新计算并检索该字段的值。


此机制允许较低级别的应用创建以延迟的方式按需计算的LiveData对象。ViewModel对象可以轻松获取对LiveData对象的引用,然后在其基础上定义转换规则。




### 最后:学习总结——Android框架体系架构知识脑图(纯手绘xmind文档)

学完之后,若是想验收效果如何,其实最好的方法就是可自己去总结一下。比如我就会在学习完一个东西之后自己去手绘一份xmind文件的知识梳理大纲脑图,这样也可方便后续的复习,且都是自己的理解,相信随便瞟几眼就能迅速过完整个知识,脑补回来。

下方即为我手绘的Android框架体系架构知识脑图,由于是xmind文件,不好上传,所以小编将其以图片形式导出来传在此处,细节方面不是特别清晰。但可给感兴趣的朋友提供完整的Android框架体系架构知识脑图原件(包括上方的面试解析xmind文档)
![](https://img-blog.csdnimg.cn/img_convert/c78d9422d32249cca36e57f7662768d6.webp?x-oss-process=image/format,png)

除此之外,前文所提及的Alibaba珍藏版 **Android框架体系架构** 手写文档以及一本 **《大话数据结构》** 书籍等等相关的学习笔记文档,也皆可分享给认可的朋友!

——感谢大家伙的认可支持,请注意:点赞+点赞+点赞!!!



**网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。**

**[需要这份系统化学习资料的朋友,可以戳这里获取](https://bbs.youkuaiyun.com/topics/618156601)**

**一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**

一本 **《大话数据结构》** 书籍等等相关的学习笔记文档,也皆可分享给认可的朋友!

——感谢大家伙的认可支持,请注意:点赞+点赞+点赞!!!



**网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。**

**[需要这份系统化学习资料的朋友,可以戳这里获取](https://bbs.youkuaiyun.com/topics/618156601)**

**一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值