How to change value of LiveData and not notify the observers

Viewed 3945

In some cases, I want to change the value of LiveData and don't want the observers to notify about the change. How can I do that?

3 Answers

I would just use Pair<T, Boolean> as the value type, and the observers can check pair.second

The idea is simple. Replace your MutableLiveData<String> with MutableLiveData<Pair<String, Boolean>>

When you want to notify the observers with value s, just call liveData.setValue(new Pair(s, true)) and call liveData.setValue(new Pair(s, false)) otherwise

on the observer side, just check the pair.second to distinguish these two cases

Edit: I was using phone to answer the question and it seems stackoverflow hides characters surrounded by angle brackets.

I think my custom class will help you

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();
        }
    }
}

Use it this way

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

The same class described in the accepted answer but overridden in the Kotlin and with AndroidX imports:

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)
    }

}
Related