前言
只要使用過一段時間的LiveData就會發現,LiveData會經常多次回調數據。我們經常碰到的這個問題。
問題復現
我們的ViewModel里是給Activity持有的並且里面有一個LiveData數據,我們A_Fragment現在獲得Activity的ViewModel並且注冊LiveData數據成為觀察者,這個時候我們setValue()就會讓前台的A_Fragment得到一次LiveData數據,接下來操作 A_Fragment 啟動 B_Fragment,在返回到A_Fragment。 你會發現只要再次注冊LiveData的observe(this, new Observer ...),那么A_Fragment里面又會接收到一次LiveData的數據。
為什么會這樣呢?
1.一部分原因是LiveData的機制,就是向所有前台Fragment或者Activity發送數據。只要注冊的觀察者在前台就必定會收到這個數據。
2.另一部分的原因是對ViewModel理解不深刻,理論上只有在Activity保存的ViewModel它沒被銷毀過就會一直給新的前台Fragment觀察者發送數據。我們需要管理好ViewModel的使用范圍。 比如只需要在Fragment里使用的ViewModel就不要給Activity保管。而根Activity的ViewModel只需要做一下數據共享與看情況使用LiveData。
解決問題
第一種方法
就是管理好ViewModel的范圍,如果業務范圍只跟某個Fragment有關,那么最好就只給這個Fragment使用。這樣Fragment在銷毀或者創建的時候,也會銷毀ViewModel與創建ViewModel,ViewModel攜帶的LiveData就是全新的不會在發送之前設置的數據。
第二種方法
就是使用一個google大神實現的一個復寫類 SingleLiveEvent,其中的機制是用一個原子 AtomicBoolean記錄一次setValue。在發送一次后在將AtomicBoolean設置為false,阻止后續前台重新觸發時的數據發送。
import androidx.annotation.MainThread; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.lifecycle.LifecycleOwner; import androidx.lifecycle.MutableLiveData; import androidx.lifecycle.Observer; import java.util.concurrent.atomic.AtomicBoolean; public class SingleLiveEvent<T> extends MutableLiveData<T> { private final AtomicBoolean mPending = new AtomicBoolean(false); @Override public void observe(@NonNull LifecycleOwner owner, @NonNull final Observer<? super T> observer) { super.observe(owner, new Observer<T>() { @Override public void onChanged(@Nullable T t) { if (mPending.compareAndSet(true, false)) { observer.onChanged(t); } } }); } @MainThread public void setValue(@Nullable T t) { mPending.set(true); super.setValue(t); } /** * Used for cases where T is Void, to make calls cleaner. */ @MainThread public void call() { setValue(null); } }