• Android开发 SingleLiveEvent解决LiveData或者MutableLiveData多次回调的问题


    前言

      只要使用过一段时间的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);
        }
    }
  • 相关阅读:
    用于Delphi的DevExpress VCL组件——富文本编辑功能升级
    5个技巧,教你优化React App性能
    DevExpress WPF模板库助力快速完成界面美化
    Web开发小技巧放送
    WinForm应用界面开发入门指南
    浅析C#中单点登录的原理和使用
    Wireshark抓包,带你快速入门
    你必须知道的EF知识和经验
    你知道SqlDataAdapter中的Fill是怎么实现的吗
    一文说通C#中的异步编程
  • 原文地址:https://www.cnblogs.com/guanxinjing/p/12669506.html
Copyright © 2020-2023  润新知