0

我有一个 livedata,每次数据库中有更新时都会发出。当特定屏幕打开时,此 livedata 会立即发出数据库中的任何值。然后,进行网络调用以更新数据库。更新数据库后,livedata 再次发出。这导致非常快速的连续两次排放。对数据库的后续更新工作正常,因为每当更新数据库时只有一次发射。只有第一次,很快就连续更新了 2 次。我想避免这种情况。

避免这种情况的想法是这样的。当 livedata 发出时,等待 Xs。如果这些 X 中有另一个发射,则丢弃旧发射中的数据并使用新发射。再次等待Xs。如果这些 X 中没有排放,请使用最新数据。

这看起来与节流非常相似,但只有一次。我想知道是否有一种简单的方法可以使用 LiveData 或 MediatorLiveData。

4

3 回答 3

0

您可以在第一个事件之后延迟发布Runnable您想要的超时。LiveData每次LiveData更新都删除发布Runnable并再次发布。

于 2020-06-18T13:10:03.250 回答
0

您可以使用 MediatorLiveData 和一个布尔值来实现这一点。

  1. 当从 API 加载数据时,创建一个 mDbLiveData、中介 livedata mFinalLiveData 和 boolean mLoadedFromAPI。
  2. 在 API 成功或失败时,将 mLoadedFromAPI 设置为 true;
  3. 在 Activity/Fragment 中观察 mFinalLiveData
LiveData<Model> mDbLiveData;
MediatorLiveData<Model> mFinalLiveData = new MediatorLiveData();
private boolean mLoadedFromAPI = false;

// Load db data in mDbLiveData
mDbLiveData = // Data from DB
// Add mDbLiveData as source in mFinaliveData
mFinalLiveData.addSource(mDbLiveData, dbData -> {
    if (mLoadedFromAPI) mFinalLiveData.postValue(dbData);
});

于 2020-06-18T14:24:38.400 回答
0

这篇文章有帮助。https://medium.com/@guilherme.devel/throttle-operator-with-livedata-and-kotlin-coroutines-ec42f8cbc0b0

我稍微修改了解决方案以适合我的用例:

fun <T> LiveData<T>.debounceOnce(duration: Long,
                                 coroutineContextProvider: CoroutineContextProvider): LiveData<T> {
    return MediatorLiveData<T>().also { mediatorLivedata ->
        var shouldDebounce = true
        var job: Job? = null
        val source = this

        mediatorLivedata.addSource(source) {
            if (shouldDebounce) {
                job?.cancel()
                job = CoroutineScope(coroutineContextProvider.IO).launch {
                    delay(duration)
                    withContext(coroutineContextProvider.Main) {
                        mediatorLivedata.value = source.value
                        shouldDebounce = false
                    }
                }
            } else {
                job?.cancel()
                mediatorLivedata.value = source.value
            }
        }
    }
}

open class CoroutineContextProvider @Inject constructor() {
    open val Main: CoroutineContext by lazy { Dispatchers.Main }
    open val IO: CoroutineContext by lazy { Dispatchers.Default }
}
于 2020-06-19T10:41:43.597 回答