美文网首页
细说Jetpack中那些LiveData们

细说Jetpack中那些LiveData们

作者: 要早点睡 | 来源:发表于2021-12-17 16:38 被阅读0次

    1)低调的CoroutinLiveData

    liveData { 
        this.emit("data") //1处
    }.observe(owner){
        data -> doSomething(data)//2处
    }
    
    

    开局一段代码

    • liveData()全局方法,他的返回值是一个LiveData因此我们可以直接监听其返回值。
    • 最后一个参数是一个带接收者的Lambda表达式,这个lambda表达式的接收者是LiveDataScope,可以直接在代码块中(1处)中调用其emit方法,向LiveData发值。
    • 方法构建了一个CoroutineLiveData返回。
    public fun <T> liveData(
        context: CoroutineContext = EmptyCoroutineContext,
        timeout: Duration,
        @BuilderInference block: suspend LiveDataScope<T>.() -> Unit
    ): LiveData<T> = CoroutineLiveData(context, timeout.toMillis(), block)
    
    

    CoroutineLiveData继承MediatorLiveData(下一章节介绍MediatorLiveData)

    1.1)block代码块中的代码执行时机会执行多次吗?

    • block中的代码会在LiveData标为活跃状态后只执行,且正常情况下只会执行一次。LiveData的非活跃到活跃状态的切换发生在注册在其身上的活跃的observer从0变为1时。
    • 当因为LiveData的状态由活跃状态变为非活跃状态的时候,会发起取消掉代码块中的任务,但会有个时间间隔,超过了时间LiveData还未恢复活跃态时,会被取消掉。这个超时时间默认为5s。
    • 因为上述原因被取消掉的任务还会被重新执行。一旦执行成功了就不会再执行。

    内部实现代码有删减只保留关键部分。

    internal class CoroutineLiveData<T>(
        context: CoroutineContext = EmptyCoroutineContext,
        timeoutInMs: Long = DEFAULT_TIMEOUT,
        block: Block<T>
    ) : MediatorLiveData<T>() {
        private var blockRunner: BlockRunner<T>?
        init {
            val supervisorJob = SupervisorJob(context[Job])
            val scope = CoroutineScope(Dispatchers.Main.immediate + context + supervisorJob)
            //注释3.对象创建时会构建一个BlockRunner对象
            blockRunner = BlockRunner(   liveData = this,block = block,timeoutInMs = timeoutInMs, scope = scope)     
             {
                blockRunner = null//注释4 最后一个参数是,此处会在代码块执行到末尾时执行。
            }
        }
        override fun onActive() {
            super.onActive()
            blockRunner?.maybeRun() //注释5 活跃时尝试执行代码块,如果blockRunner为空就不会执行
        }
    }
    
    internal class BlockRunner<T>(..) {
        private var runningJob: Job? = null
        @MainThread
        fun maybeRun() {
            if (runningJob != null)  return //注释7. 如果runningJob不为空也不会执行。
            runningJob = scope.launch {
               block(liveDataScope)//执行代码块
               onDone()
            }
        }
    }
    
    
    • 运行的代码块被包装在了BlockRunner内部类中,构造方法的最后一个参数会在代码块执行的最后的时候执行,也就意味着 blockRunner对象被置为null。当LiveData再次处于活跃状态时也不会执行了。

    • 一旦任务被取消成功注释8处,runningJob会被置空,注释5处 当LiveData重新处于活跃状态时block代码块就会被重新执行。

    1.2)取消的超时机制怎么实现的?

    # BlockRunner
    fun cancel() { //LiveData onInactive()时被调用
        cancellationJob = scope.launch(Dispatchers.Main.immediate) {
            delay(timeoutInMs) //注释10处
            if (!liveData.hasActiveObservers()) {
                runningJob?.cancel()
                runningJob = null //注释11
            }
        }
    }
     fun maybeRun() {
            cancellationJob?.cancel()//注释11
            cancellationJob = null
            runningJob?.cancel()
            ...
     }
    
    
    • 开启一个取消协程任务,这个协程任务中首先有个等待,在等待期间注释10下面的逻辑就得不到执行。
    • 注释11处,如果当代码块执行之前,是否有取消任务,如果有会把这取消任务给终止掉
    1. 多面手MediatorLiveData

    image.png

    2.1) 用MediatorLiveData监听其他LiveData的数据变化。

    • MediatorLiveData # addSource(LiveData<S> source, Observer<? super S> onChanged) 当sourceLiveData数据有变化后,onChanged这个Observer会的onChange方法会被回调,我们可以在这个回调里选择向MediatorLiveData设置数据。
    • (思考,为啥onChanged这个参数的泛型声明为<? super S>,有什么含义。
    • public <S> void removeSource(LiveData<S> toRemote) 这个方法可以停止对某个LiveData的监听。

    2.2) 内部实现

    private static class Source<V> implements Observer<V> {
        final LiveData<V> mLiveData;
        final Observer<? super V> mObserver;
        int mVersion = START_VERSION;
        
        void plug() {  mLiveData.observeForever(this);  }
        void unplug() { mLiveData.removeObserver(this); }
        
        @Override
        public void onChanged(@Nullable V v) {
            if (mVersion != mLiveData.getVersion()) {//会对比版本
                mVersion = mLiveData.getVersion();
                mObserver.onChanged(v);
            }
        }
    }
    
    
    • 内部实现也比较简单,MediatorLiveData内部addSource方法会把LiveData和Observer包装成一个Source如上代码段。
    • Source实现了Observer,其onChanged方法中会有天剑的调用addSource方法传入的observer(onChanged)的方法。
    1. 小透明SavingStateLiveData

    这个类的位置在 lifecycle-viewmodel-savedstate的SavedStateHandle类中,也是继承自MutableLiveData,其与MutableLiveData最大的不同是多了两个属性。

    private String mKey;
    private SavedStateHandle mHandle;
    
    

    作用是保证,LiveData所在的Viewmodel重建时,能够拿到销毁前的数据。

    1. 小结

    本文介绍了Jetpack中,LiveData比较有特点的子类。

    • CoroutinLiveData出场自带所宿主的ViewModel
    • MediatorLiveData能同时监听多个LiveData的数据变化。
    • SavingStateLiveData销毁重建时能够自动恢复销毁前的数据。

    视频:
    Android中高级进阶之MVVM与JetPack: LiveData
    资深架构师逐题详解Android大厂精选高频面试题之LiveData
    原文: https://juejin.cn/post/7034768099198894117#comment

    相关文章

      网友评论

          本文标题:细说Jetpack中那些LiveData们

          本文链接:https://www.haomeiwen.com/subject/jamifrtx.html