📜  如何在 Android 中使用 SingleLiveEvent 仅观察一次事件?(1)

📅  最后修改于: 2023-12-03 15:38:12.333000             🧑  作者: Mango

如何在 Android 中使用 SingleLiveEvent 仅观察一次事件?

在 Android 开发中,我们常常需要在不同的组件之间传递数据,例如 Activity 和 Fragment 之间、ViewModel 和 View 之间等。在传递数据的过程中,我们经常会遇到重复执行问题,即同一个事件被触发多次。为了解决这个问题,Android 官方推出了 LiveData,但 LiveData 存在一个缺点就是会在界面旋转等场景下重复触发事件。

为了解决 LiveData 的缺点,最近 Google 推荐了一种新的解决方案:SingleLiveEvent。这个类可以在 LiveData 的基础上实现只观察一次事件,避免了 LiveData 重复触发事件的缺点。

SingleLiveEvent 是什么?

SingleLiveEvent 是 LiveData 的子类,继承了 LiveData 的优点,解决了 LiveData 的缺点。SingleLiveEvent 可以实现只接收一次事件的能力。

SingleLiveEvent 的核心思想是记录观察者的状态,以避免对已经活跃的观察者多次分派事件。SingleLiveEvent 具有以下特点:

  1. SingleLiveEvent 应该只有一个活跃的观察者。
  2. 如果有多个观察者处于活动状态,SingleLiveEvent 只会通知其中一个。
  3. 如果没有观察者处于活动状态,SingleLiveEvent 不会通知任何观察者。
如何使用 SingleLiveEvent?
步骤一:添加依赖

在 app 模块的 build.gradle 文件中添加如下代码:

dependencies {
    implementation 'androidx.lifecycle:lifecycle-livedata:2.2.0'
}
步骤二:创建 SingleLiveEvent 类

创建一个继承自 LiveData 的 SingleLiveEvent 类,并重写父类的 setValue 和 postValue 方法。

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

    private final AtomicBoolean mPending = new AtomicBoolean(false);

    @MainThread
    public void observe(@NonNull LifecycleOwner owner, @NonNull final Observer<? super T> observer) {
        if (hasActiveObservers()) {
            Log.w(TAG, "Multiple observers registered but only one will be notified of changes.");
        }
        super.observe(owner, new Observer<T>() {
            @Override
            public void onChanged(T t) {
                if (mPending.compareAndSet(true, false)) {
                    observer.onChanged(t);
                }
            }
        });
    }

    @MainThread
    public void setValue(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);
    }
}
步骤三:在 View 中观察 SingleLiveEvent

在需要观察 SingleLiveEvent 的 View 中使用 observe() 方法观察 SingleLiveEvent。

singleLiveEvent.observe(this, new Observer<Boolean>() {
    @Override
    public void onChanged(Boolean aBoolean) {
        //只会回调一次
    }
});
步骤四:在 ViewModel 中使用 SingleLiveEvent

在 ViewModel 中声明 SingleLiveEvent 类型的成员变量,并在需要触发事件的地方使用 setValue() 方法触发事件。

public class MainViewModel extends ViewModel {

    private SingleLiveEvent<Boolean> mSingleLiveEvent = new SingleLiveEvent<>();

    public SingleLiveEvent<Boolean> getSingleLiveEvent() {
        return mSingleLiveEvent;
    }

    public void doSomething() {
        //触发事件
        mSingleLiveEvent.setValue(true);
    }
}
总结

SingleLiveEvent 可以有效地解决 LiveData 在界面旋转等场景下重复触发事件的问题。在大多数场景下,我们建议使用 SingleLiveEvent 来替代 LiveData,以便更好地管理事件的触发。