使用初始超时观察实时数据

时间:2020-06-18 13:04:09

标签: android android-livedata kotlin-coroutines android-livedata-transformations

我有一个livedata,每次数据库更新时都会发出。当特定屏幕打开时,该实时数据将立即发出,无论数据库中存在什么值。然后,进行网络调用以更新数据库。更新数据库后,实时数据将再次发出。这导致非常连续的两次排放。随后对数据库的更新将正常工作,因为每当更新数据库时,只有一次发射。仅是第一次,非常连续地进行了2次更新。我想避免这种情况。

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

这看起来很像节流,但只有一次。我想知道是否有一种简单的方法来执行诸如使用LiveData或MediatorLiveData的操作。

3 个答案:

答案 0 :(得分:0)

您可以在第一个Runnable事件之后按照需要的超时发布延迟的LiveData。 每个LiveData更新都会删除已发布的Runnable,然后再次发布。

答案 1 :(得分:0)

您可以使用MediatorLiveData和布尔值来实现此目的。

  1. 从API加载数据时,创建一个mDbLiveData,中介者livedata mFinalLiveData和布尔mLoadedFromAPI。
  2. 在API成功或失败时,将mLoadedFromAPI设置为true;
  3. 在“活动/片段”中观察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);
});

答案 2 :(得分: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 }
}