Android LiveData prevent receive the last value on observe

后端 未结 12 1309
自闭症患者
自闭症患者 2020-11-27 04:41

Is it possible to prevent LiveData receive the last value when start observing? I am considering to use LiveData as events.

For example eve

12条回答
  •  暖寄归人
    2020-11-27 05:33

    I created a LiveData object FreshLiveData, which emits the onChange to the observer only after there is a call to setValue or postValue.

    FreshLiveData.kt

    /**
     * A lifecycle-aware observable that emits only new data after subscription. Any data that has
     * already been set, before the observable has subscribed, will be ignored.
     *
     * This avoids a common problem with events: on configuration change (like rotation, font change) an
     * update can be emitted if the observer is active. This LiveData only calls the observable if
     * there's an explicit call to setValue() or postValue().
     *
     * All observers will be notified of change(s).
     */
    class FreshLiveData : MutableLiveData() {
    
        private val observers = mutableMapOf()
    
        override fun observe(owner: LifecycleOwner, observer: Observer) {
            @Suppress("UNCHECKED_CAST")
            observer as Observer
            observers[owner].apply {
                if (this == null) {
                    observers[owner] = FreshLiveDataObserver(observer).apply {
                        super.observe(owner, this)
                    }
                } else {
                    add(observer)
                }
            }
        }
    
        override fun observeForever(observer: Observer) {
            @Suppress("UNCHECKED_CAST")
            observer as Observer
            observers[ProcessLifecycleOwner.get()].apply {
                if (this == null) {
                    observers[ProcessLifecycleOwner.get()] = FreshLiveDataObserver(observer).apply {
                        super.observeForever(this)
                    }
                } else {
                    add(observer)
                }
            }
        }
    
        override fun removeObservers(owner: LifecycleOwner) {
            observers.remove(owner)
            super.removeObservers(owner)
        }
    
        override fun removeObserver(observer: Observer) {
            @Suppress("UNCHECKED_CAST")
            observers.forEach { it.value.remove(observer as Observer) }
            super.removeObserver(observer)
        }
    
        @MainThread
        override fun setValue(t: T?) {
            observers.forEach { it.value.setPending() }
            super.setValue(t)
        }
    
        override fun postValue(value: T) {
            observers.forEach { it.value.setPending() }
            super.postValue(value)
        }
    
        inner class FreshLiveDataObserver(observer: Observer) : Observer {
            private val observers = mutableSetOf>()
            private val pending = AtomicBoolean(false)
    
            init {
                observers.add(observer)
            }
    
            fun add(observer: Observer) = observers.add(observer)
            fun remove(observer: Observer) = observers.remove(observer)
            fun setPending() = pending.set(true)
    
            override fun onChanged(t: T) {
                if (pending.compareAndSet(true, false)) {
                    observers.forEach { observer ->
                        observer.onChanged(t)
                    }
                }
            }
    
        }
    }
    

    and here is an extension for transforming an existing LiveData to a FreshLiveData.

    LiveDataExtensions.kt

    @MainThread
    fun  LiveData.toFreshLiveData(): LiveData {
        val freshLiveData = FreshLiveData()
        val output = MediatorLiveData()
        // push any onChange from the LiveData to the FreshLiveData
        output.addSource(this) { liveDataValue -> freshLiveData.value = liveDataValue }
        // then push any onChange from the FreshLiveData out
        output.addSource(freshLiveData) { freshLiveDataValue -> output.value = freshLiveDataValue }
        return output
    }
    

    Usage:

    val liveData = MutableLiveData()
    liveData.value = false
    liveData.toFreshLiveData().observeForever {
        // won't get called with `it = false` because the observe was setup after setting that livedata value
        // will get called with `it = true` because the observer was setup before setting that livedata value
    }
    liveData.value = false
    
    val freshLiveData = FreshLiveData()
    freshLiveData.value = false
    freshLiveData.observeForever {
        // won't get called with `it = false` because the observe was setup after setting that livedata value
        // will get called with `it = true` because the observer was setup before setting that livedata value
    }
    freshLiveData.value = true
    

提交回复
热议问题