Livedata

LiveData简介

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

其实 LiveData 就是 一个 自己更改数据,并且,只要数据一变,自己设置的观察者们就会自动调用change方法,并且获取新数据的值,而你就可以在change方法中,做出数据改变后要做的相应的对应逻辑,比如说UI改变等操作,但是,并不是数据一改变,监听者们就会被调用,livedata是配合lifecycle的,也就是可以设置一个 被观察者lifcecycleOwner,,比如activity,fragment,service ,当设置了一个被观察者的时候,就会只在被观察者也就是activity的生命周期可见也就是 onstart onresume on pause 被调用之后的时候,这些监听者们才会被调用,当activity不可见的,也就是生命周期走 oncreate onstrop,ondestroy,之后,livedata依旧能够更改数据,只是那些监听者们不会在被调用。

LiveData的基本使用

最简单的使用如下:

class MainActivity : AppCompatActivity() {


    val TAG = "zjs"

     //livadata使用的是MutableLiveData这个类去存储数据
    var data : MutableLiveData<String> = MutableLiveData<String>()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

      
 
       //livedata 调用observe方法,第一个参数就是被观察者,也就是LifecycleOwner ,而第二个参数就是个观察者,
       //当数据livedata里面存放的数据发生变化的时候,观察者的change就会被调用,并且参数就是新的值
       //不过因为设置observe监听的时候,多设置了一个被观察者是this,也就是当前的 MainActivity  所以,只有当 MainActivity  的可见生命周期的时候,
       //该监听者才会被调用。否则不会被调用。
        data.observe(this,object:Observer<String>{
            override fun onChanged(t: String?) {
                 Log.d(TAG, "onCreate: it $it" )
                 // 在这里手动更改textview显示的文案,这样就可以做到当在 MainActivity 可见的时候,当livedata的数据改变,textview的文案也会自动更正改变,做到
                 //在界面可见的时候,数据改变,界面也会跟着改变
                 textview.setText(t)
            }
        })
  
      //这种是lambda的写法
        data.observe(this, Observer {
            Log.d(TAG, "onCreate: it $it" )
        })

     最终简化就是
      data.observe(this){
            Log.d(TAG,"onCreate:it$it")
      }

        
        //在主线程中通过setvalue 的方式改变livedata里面的数据
        data.value = "zjs"

 

     
    }
}

注意,livedata 设置 观察者 observe 只能在主线程设置,不能在子线程

上面是livedata是在主线程中更改自身的数据,但是在实际项目中,很多时候,也需要在子线程中更改数据,这个时候就得调用
data.postValue(“”) ,而不能是 setValue,也就是



//在大多数情况也需要在子线程改变数据,然后主线程的监听者们,一样也可以收到数据改变监听并获取到新数据,当然一样是在被观察者的可见才会调用
  thread {
            data.postValue("子线程更改数据")
        }

当然postValue内部其实 是从通过Handle 子线程切换回主线程然后在主线程再次调用setValue

注意 LiveData的接收确实是在主线程进行的,也就是可以用livedata 去在子线程或者主线程,但是观察者onchannge,只能在主线程

前面说的都是livedata 调用obsever方法设置了一个被观察者,比如MainActivity,然后需要跟着MainActivity的生命周期可不可见决定 设置的观察者们数据改变的时候是否能被调用监听到,livedata同样也提供了一个api方法,能够不设置这个被观察者,也就是,livedata他的数据在改变,在任何时候监听者们都能够知道监听到,不在依赖任何人的生命周期,就是调用 observeForever方法

  data.observeForever(object :Observer<String>{
            override fun onChanged(t: String?) {
                TODO("Not yet implemented")
            }

        })

你看,这里 observeForever方法参数就不再需要有一个被观察者了,而是仅仅设置监听者,这样的话 只要在任何时候livedata的数据改变,监听者们都可以获取到。但是这里再项目场景很多时候都会造成内存泄漏,所以再不需要的时候,要记得及时的removeObserver

  var observer = Observer<String> {
            textView.setText(it)
        }

        data.observeForever(observer)

        data.removeObserver(observer)

注意一点livedata的 使用 ,估计会因为此问题引起业务上的 bug

正常逻辑情况下,我们是先设置监听, 然后livedata再改变数据,然后在数据改变,监听到 根据业务做出自己的需要逻辑。

但是livedata是会有粘性事件的 ,也是就, livedata先 改变数据 ,再设置监听,这时候,上一次数据的改变 他也是会收到消息的 监听 onchange 方法 也是被调用,还有,如果你 livedata 改变了6次,然后在 再设置监听 ,那么收到数据只有最后第6次改变的数据, 这种 livedata有粘性事件 并不是bug,只是google就是这么设计,也就是它会收到你设置监听前的最后一次数据 ,至于原理,以及防止收到上一次粘性事件 在下面的原理有说明

所以你需要根据自己的业务情况,打印下日志看看会不会引起,不想接收到消息的时候,多收了粘性事件的消息,而导致业务上的bug问题

Transformations.map操作符

Transformations.map 可以对 LiveData 的数据在分发给观察者之前进行转换,然后返回一个新的 LiveData 对象。

使用如下

    fun transformationsMapTest() {
        //原本的 originLiveData
        val originLiveData = MutableLiveData<Int>()

        //数据转换,将原始数据进行转换,其实就添加一个叠加
        //在这里,也就是会把 originLiveData 存放的Int  进行乘以 2 的操作
        // 然后 transformLiveData 添加的观察者们收到的数据就是,
        // originLiveData 的数据乘以2
        val transformLiveData: LiveData<Int> = Transformations.map(originLiveData) { input ->
            input * 2
        }

        // 后续使用的是 转换后生成的transformLiveData去观察数据,而不是 originLiveData 去添加
        //因为 用 originLiveData就没有  transformLiveData 的 意义了
        transformLiveData.observe(this) { output ->
            LogUtil.e("transformationsMap 数据转换变化:$output") //这里就会打印 20
        }

        //使用原始的LiveData 去改变数据,10 
        originLiveData.value = 10
    }

livedata 的原理解析

大概如下:

livedata 它能够 根据lifecycleOwner 生命周期判断是否 调用 观察者们observe的change 方法,就是靠的lifecycle,
根据lifecycle 原理 就可知道,是lifecycle内部定义了acitiviy 的生命周期各种State,以及observe观察者们当前的状态,
然后根据 acitiviy 的生命周期变化,主动调用 LifecycleEventObserver 的 onStateChanged ,然后具体调用
LifecycleEventObserver 的实现类 lifecycleBoundObserver 的 onStateChanged 方法,livedata设置的Observer就是
封装在 lifecycleBoundObserver 里头,

接着

把 lifecycleOwner 的刚变化
生命周期 传送Event onStateChanged 的参数中去,然后在 lifecycleBoundObserver 的 onStateChanged 中
会根据 shouldBeActive 方法判断 当前的Event,也就是 lifecycleOwner 当前的 生命周期是否是 激活状态 true 状态
也就是lifecycleOwner 的 State 是 如果生命周期是 STARTED 和 RESUMED ,也就是对应 生命周期
是 onStart onResume onPause 就是激活状态,而其他的生命周期就不是,也是就激活状态才会调用
observe.onchange 方法,从而做到了根据 lifecycleOwner 的生命周期,livedata数据改变的时候 ,livedata 观察者们
是否被调用。

具体详细如下:

livedata的参数接受两个,第一个参数是宿主,也就是LifecycleOwner ,正是因为 LifecycleOwner 里面有lifecycle
那么也就是用此LifecycleOwner 的 lifecycle 去 根据 LifecycleOwner 的生命周期状态判断处理

而第二个参数就是 观察者们 Observer

当通过
livedata.observe 添加一个Observer 的时候,
就会把 这个 Observer 封装到 lifecycleBoundObserver 里,而 lifecycleBoundObserver又是 LifecycleEventObserver 的
其中一个具体实现类

根据 lifecycle 的篇章知道,

lifecycle要通知 观察者们做事情的时候会

调用 LifecycleEventObserver 这个接口实例的 .onStateChanged 方法 而这里具体实现类就是 lifecycleBoundObserver 的 onStateChanged方法

在这里插入图片描述

并且在这里也会把这个 observer push 到 mObservers list 中去,为的是,等待要根据它循环告诉所有的 observer
在这里插入图片描述

回过头来先总结下,也就是当lifecycleOwner 的生命周期发送改变的时候,lifecycle会调用
LifecycleEventObserver .onStateChanged 方法 进而调用 lifecycleBoundObserver 的 onStateChanged方法

而在这个方法中会先 lifecycleOwner 的生命周期判断当前是否是mActive = true 状态,
判断方法为 shouldBeActive

在这里插入图片描述
并且把这个状态调用 activeStateChanged 方法

在这里插入图片描述

然后在 activeStateChanged 方法中 如果是激活状态就是调用 dispatchingValue(this); 注意这里的
dispatchingValue 方法传入的是this,而不是null

在这里插入图片描述
在这里插入图片描述

这里是根据传入的是this 还是null 做链路区分的,如果传入是this,其实代表livedata 还没 改变数据,也就是还没 setValue
或者postValue,只是在代码设置监听的状态, 后续livedata 还没 setValue 或者postValue ,而是还没 setValue 或者postValue之前 生命周期发送了改变, 把上一次的 还没 设置监听前的 最后一次 setvalue 事件给发送出去
也就是上面所说的 粘性事件

正因为传入的是 this, 不是null

关键走了 considerNotify 这个方法 并且参数传进去

在这里插入图片描述

当你每次setValue 的时候,mVersion++; 就会++

注意这就是粘性事件的由有,因为一开始,你先 setValue ,而 每次SetValue 的时候mVersion++,
也是你从-1变成了0,然后你再设置监听,在还没有 再 SetValue 的时候,根据上面的链路

observer.mLastVersion =-1,而 mVersion =1
所有会走 return,所以会走到 observer.mObserver.onChanged((T) mData); 所以才会把 刚刚设置监听前的最后一条数据
改变也给传送过来,观察者还是能收到最后一条数据, 那么如果你想解决此问题 ,就是通过反射,当设置监听的时候
通过反射,当 mVersion !=-1, 也就是 我还没 设置监听,你的值版本就改变了,那么我在设置监听的时候 就得把 observer.mLastVersion 改成 mVersion 的一样 ,那么 当我设置监听的时候,就认为他们 一样就走 return
就不会触发观察者收到监听。

上面说的是设置完监听还没有改变值,只是生命周期改变,然后粘性事件的发送 的链路情况

而当你后续 利用livedata setValue 或者postValue的时候

你看当你每次setValue 的时候,mVersion++; 就会++,并且,会调用 dispatchingValue(null); 而这次不像在刚设置监听状态那时候,生命周期改变 调用的 dispatchingValue(this)

在这里插入图片描述

正是因为传入的是null 所以走的是这里

在这里插入图片描述

正因为 setValue 的时候,mVersion++
所以 observer.mLastVersion 肯定跟刚才改变的 mVersion 不一样 所以不走return

所以会变量各个观察者的 onChanged方法

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值