如何更改LiveData的值而不通知观察者

4
在某些情况下,我想要改变LiveData的值,但不希望观察者被通知到这一变化。我该如何做到这一点?

你应该始终期望通知观察者,这就是观察者模式的关键。 - EpicPandaForce
3个回答

11
我会建议使用Pair<T, Boolean>作为值类型,观察者可以检查pair.second
这个想法很简单。用MutableLiveData<Pair<String, Boolean>>替换你的MutableLiveData<String>
当你想要通知观察者值为s时,只需调用liveData.setValue(new Pair(s, true)),否则调用liveData.setValue(new Pair(s, false))
在观察者方面,只需检查pair.second以区分这两种情况。
编辑:我使用手机回答问题,似乎stackoverflow会隐藏被尖括号包围的字符。

你能否详细解释一下...? - Morteza Rastgoo

6

我认为我的自定义类会对你有所帮助

import android.arch.lifecycle.Lifecycle;
import android.arch.lifecycle.LifecycleOwner;
import android.arch.lifecycle.MutableLiveData;
import android.arch.lifecycle.Observer;
import android.support.annotation.MainThread;
import android.support.annotation.NonNull;
import android.util.Pair;

import java.util.ArrayList;
import java.util.List;

public class SSBLiveData<T> extends MutableLiveData<T> {

    private List<Pair<LifecycleOwner, Observer>> observers = new ArrayList<>();

    @MainThread
    @Override
    public void observe(@NonNull LifecycleOwner owner, @NonNull final Observer observer) {
        observers.add(new Pair<>(owner, observer));
        super.observe(owner, observer);
    }

    @MainThread
    private void resetAllObservers() {
        for (Pair<LifecycleOwner, Observer> observer : observers) {
            super.observe(observer.first, observer.second);
        }
    }

    @MainThread
    private void removeAllObservers() {
        for (Pair<LifecycleOwner, Observer> observer : observers) {
            removeObservers(observer.first);
        }
    }

    @MainThread
    void setValueWithoutNotify(T value) {
        removeAllObservers();
        super.setValue(value);
        System.out.println("Not notifying value " + getValue());
    }
   // For androidx use this method
   /*@MainThread
   @Override
   public void removeObserver(@NonNull Observer<? super T> observer) {
    for (Pair<LifecycleOwner, Observer> observerItem : observers) {
        if (observerItem.second.equals(observer) && observerItem.first.getLifecycle().getCurrentState() == Lifecycle.State.DESTROYED) {
            observers.remove(observerItem);
        }
    }
    super.removeObserver(observer);
   }*/

    @MainThread
    @Override
    public void removeObserver(@NonNull Observer<T> observer) {
        for (Pair<LifecycleOwner, Observer> observerItem : observers) {
            if (observerItem.second.equals(observer) && observerItem.first.getLifecycle().getCurrentState() == Lifecycle.State.DESTROYED) {
                observers.remove(observerItem);
            }
        }
        super.removeObserver(observer);
    }

    @Override
    public void setValue(T value) {
        super.setValue(value);
        if (!hasObservers()) {
            resetAllObservers();
        }
    }
}

使用方法如下:

SSBLiveData<String> liveData = new SSBLiveData<>();
liveData.setValueWithoutNotify("It won't get notified");
liveData.setValue("It will get notified");

1
这个类存在内存泄漏问题。假设您在单例类中有一个SSBLiveData实例,并且一个Activity观察它。由于SSBLiveData实例正在引用此Activity的观察者,因此此Activity将不会被垃圾回收。 - Sanlok Lee
1
@SanlokLee 感谢您指出问题,我已经修复了 SSBLiveData 类,现在它不会有内存泄漏了,请检查我的编辑答案。 - SSB
我遇到了错误:'com.behkameh.daggersample.util.SSBLiveData' 中的 'removeObserver(Observer<T>)' 与 'androidx.lifecycle.LiveData' 中的 'removeObserver(Observer<? super T>)' 产生冲突;两个方法具有相同的擦除,但都没有覆盖另一个。 - Morteza Rastgoo
这是因为您正在使用androidx,并且androidx库的LiveData发生了一些变化。我已经编辑了我的答案,并添加了用于androidx的removeObserver方法,请检查我的编辑后的答案。 - SSB

2

与被接受的答案中描述的相同的类,但在 Kotlin 中进行了重写,并使用了 AndroidX 导入:

import android.util.Pair
import androidx.annotation.MainThread
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.Observer
import java.util.*

class ExtendedLiveData<T>() : MutableLiveData<T>() {

    private val observers: MutableList<Pair<LifecycleOwner, Observer<in T>>> = ArrayList()

    @MainThread
    override fun observe(owner: LifecycleOwner, observer: Observer<in T>) {
        observers.add(Pair(owner, observer))
        super.observe(owner, observer)
    }

    @MainThread
    private fun resetAllObservers() {
        for (observer in observers) {
            super.observe(observer.first, observer.second)
        }
    }

    @MainThread
    private fun removeAllObservers() {
        for (observer in observers) {
            removeObservers(observer.first)
        }
    }

    @MainThread
    fun setValueWithoutNotify(value: T) {
        removeAllObservers()
        super.setValue(value)
        println("Not notifying value " + getValue())
    }

    @MainThread
    override fun removeObserver(observer: Observer<in T>) {
        for (observerItem in observers) {
            if (observerItem.second == observer && observerItem.first.lifecycle
                    .currentState == Lifecycle.State.DESTROYED
            ) {
                observers.remove(observerItem)
            }
        }
        super.removeObserver(observer)
    }

    override fun setValue(value: T) {
        super.setValue(value)
        if (!hasObservers()) {
            resetAllObservers()
        }
    }

    fun resetValue() {
        super.setValue(null)
    }

}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接