【Jetpack】学穿:LiveData → ???(中)

简介: 在开始这篇文章前,我就遇到了第一个关于LiveData的问题:该怎么翻译这个词呢?

回调了 onStateChanged() 方法,符合第二种场景 → 生命周期组件状态变更


网络异常,图片无法展示
|


activeStateChanged()dispatchingValue()considerNotify()


网络异常,图片无法展示
|


粘性的原因到此就一清二楚了,此处应有掌声!!!


怎么解决粘性问题?不急,等下讲,这里TM才开头而已,LiveData用法都还没介绍呢。


⑤ 数据驱动


简单点说:不需要主动给界面推(设置数据),界面会被动观察数据变化。


0x2、LiveData 使用详解


老规矩,官方文档双手奉上:《LiveData 概览》,以官方文档和源码为准~


① 依赖组件


LiveData基本配着ViewModel一起用的,你实在不想依赖,可以按官方文档的来:Lifecycle


def lifecycle_version = 2.4.1
// Java项目
implementation "androidx.lifecycle:lifecycle-livedata:$lifecycle_version"
// Kotlin项目
implementation "androidx.lifecycle:lifecycle-livedata-ktx:$lifecycle_version"


咳,如果你启用了DataBinding,可以不用另外依赖,不然你会发现两个版本的livedata:


网络异常,图片无法展示
|


命令行键入:gradlew :app:dependencies > dependencies.txt 扫一波就知道了:


网络异常,图片无法展示
|


② 创建、观察、更新


创建就不用说了,LiveData是抽象类,要么继承自定义,要么用 MutableLiveData

观察、更新在粘性那里的例子已经演示得很清楚了,就不Copy了,这里提一嘴 添加观察者的两个方法


  • observe() → 当生命周期组件处于STARTED和RESUMED状态下才会收到分发值。
  • observeForever() → 跟生命周期组件状态没关系了,都会收到分发值,要手动调 removeObserver() 移除!


还有 两种改变数据的方法


  • setValue() → 只能在主线程中调用;
  • postValue() → 既可以在主线程中调用,也可以在子线程中调用,最终调用的还是setValue();


③ 为什么LiveData搭配ViewModel使用?


  • 1、避免Activity、Fragment的代码臃肿,不塞ViewModel里也要做数据和组件分离;


  • 2、将LiveData与特定的Activity、Fragment分离,配置发生更改(如旋转)导致重建,不影响LiveData。


④ LiveData扩展


就是LiveData预留了两个回调:onActive()onInactive(),当生命周期组件 在活跃和非活跃状态间切换 时会回调。


网络异常,图片无法展示
|


可以怎么玩?比如写一个全局可用的倒计时器,先写倒计时相关功能:


object CountDownManager {
    private var mRemainSecond: Long = 10L
    private var mTimer: CountDownTimer? = null
    private var mListener = arrayListOf<CountDataChangeListener>()
    // 开始倒计时
    fun startCount(remainSecond: Long? = 10L) {
        mRemainSecond = remainSecond!!
        mTimer = object: CountDownTimer(remainSecond * 1000, 1000) {
            override fun onTick(millisUntilFinished: Long) {
                mRemainSecond--
                dispatchMessage("剩余:$mRemainSecond 秒")
            }
            override fun onFinish() {
                dispatchMessage("倒计时结束")
            }
        }
        mTimer!!.start()
    }
    // 取消倒计时
    fun cancelCount() {
        if(mTimer != null) {
            mTimer!!.cancel()
            mListener.clear()
        }
    }
    // 遍历回调方法
    private fun dispatchMessage(msg: String) { mListener.forEach { it.onChange(msg) } }
    // 添加监听器
    fun setListener(listener: CountDataChangeListener) { mListener.add(listener) }
    // 移除监听器
    fun removeListener(listener: CountDataChangeListener) { mListener.remove(listener) }
}
// 回调接口
interface CountDataChangeListener{
    fun onChange(msg: String)
}


非常简单,就是初始化倒计实例,遍历回调而已,接着继承LiveData,写一个全局数据类:


class GlobalLiveData : LiveData<String>() {
    companion object {
        private lateinit var instance: GlobalLiveData
        fun getInstance() = if (::instance.isInitialized) instance else GlobalLiveData()
    }
    private val mListener = object : CountDataChangeListener {
        override fun onChange(msg: String) {
            postValue(msg)  // 调用更新数据的方法
        }
    }
    fun startCount(remainSecond: Long? = 10L) { CountDownManager.startCount(remainSecond) }
    fun cancelCount() { CountDownManager.cancelCount() }
    // 活跃时添加监听器
    override fun onActive() {
        super.onActive()
        CountDownManager.setListener(mListener)
    }
    // 不活跃时移除监听器
    override fun onInactive() {
        super.onInactive()
        CountDownManager.removeListener(mListener)
    }
}


然后是调用处:


// 添加倒计时监听
GlobalLiveData.getInstance().observe(this) { mBinding.tvTest.text = it }
// 开始倒计时
GlobalLiveData.getInstance().startCount(30)


你只管添加观察,无需担心移除,页面 (Activity、Fragment) 不活跃时不更新页面,活跃时才更新。运行效果如下:


网络异常,图片无法展示
|


Tips:只是写下例子,真正用到项目还得自己改下哈,如添加/移除观察者时加锁 ~


⑤ LiveData转换


Lifecycle包提供了 Transformations 来对LiveData的数据类型进行转换,可以 在数据返回给观察者前,修改LiveData中数据的具体类型


Transformations 中有两个常用的转换方法 map()swtichMap(),它们都是使用 MediatorLiveData 作为数据的中间消费者,并将转换后的数据传递给最终消费者。


Transformations.map()


先看下map()的具体实现:


网络异常,图片无法展示
|


流程解读


  • 实例化一个 MediatorLiveData 实例 result
  • 调用 addSource() 传入 源LiveData新建的Observer实例
  • 在Observer的回调方法onChange()中,把 转换函数的执行结果 传入result的setValue()方法中;
  • 最后返回result;


跟下:MediatorLiveData.addSource()


网络异常,图片无法展示
|


用Source包了一层,将传入参数关林,直接跟 Source.plug()


网络异常,图片无法展示
|



相关文章
|
6月前
|
前端开发 Java API
Jetpack MVVM 七宗罪之五: 在 Repository 中使用 LiveData
Jetpack MVVM 七宗罪之五: 在 Repository 中使用 LiveData
115 0
|
6月前
|
前端开发 JavaScript Android开发
Jetpack MVVM 七宗罪之四: 使用 LiveData/StateFlow 发送 Events
Jetpack MVVM 七宗罪之四: 使用 LiveData/StateFlow 发送 Events
144 0
|
4月前
|
XML 存储 API
Jetpack初尝试 NavController,LiveData,DataBing,ViewModel,Paging
Jetpack初尝试 NavController,LiveData,DataBing,ViewModel,Paging
|
Android开发
Android JetPack组件之LiveData的使用详解
Android JetPack组件之LiveData的使用详解
156 0
Android JetPack组件之LiveData的使用详解
|
前端开发 数据处理 调度
Android 基于Jetpack LiveData实现消息总线
在Android开发中,跨页面传递数据(尤其是跨多个页面传递数据)是一个很常见的操作,可以通过Handler、接口回调等方式进行传递,但这几种方式都不太优雅,**消息总线**传递数据的方式相比更优雅。
326 0
|
存储 Android开发 数据格式
Android Jetpack系列之LiveData
**LiveData是一种可观察的数据存储类**。LiveData 具有生命周期感知能力,遵循其他应用组件(如 Activity、Fragment 或 Service)的生命周期。这种感知能力可确保 LiveData 仅更新处于活跃生命周期状态的Observer,非活跃状态下的Observer不会受到通知。
140 0
|
Android开发
安卓Jetpack狠活——Lifecycles与LiveData(二)
书接上回,我们看过了LiveData的使用,自然也就明白了这玩意虽然好,但不能处处到位,因为需要你自己去post后才能得到,那如何不用在子线程一直苦苦等待就能给人一种在实时更新的感觉呢?那自然要用到我们的狠活——Lifecycle。
135 0
|
Android开发
安卓Jetpack狠活——Lifecycles与LiveData(一)
今天在工作时,测试突然提了一个Bug给我,要求我将APP中某活动页面的UI界面要根据用户在由此页面跳转的下个页面操作,在返回时要实时更新。
115 0
|
存储 自然语言处理 前端开发
Jetpack 系列(2)—— 为什么 LiveData 会重放数据,怎么解决?
Jetpack 系列(2)—— 为什么 LiveData 会重放数据,怎么解决?
1210 0
Jetpack 系列(2)—— 为什么 LiveData 会重放数据,怎么解决?