前言
只要使用过一段时间的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); } }