【问题标题】:Observe livedata with an initial timeout使用初始超时观察 livedata
【发布时间】:2020-06-18 13:04:09
【问题描述】:

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

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

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

【问题讨论】:

  • 嘿,我有点困惑,你有一个正在观察数据的 livedata,当数据发生变化时你想调用网络请求,然后我们的 livedata 将再次调用。所以我们有两个发射,一个是第一次活动启动,一个是在网络请求后,你想禁用第一个观察?
  • 是的。有点像那样。我不想禁用第一次发射。如果第一次发射后没有其他发射 X,我想使用它。如果这些 X 中有发射,我想重复这个过程。

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


【解决方案1】:

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

【讨论】:

    【解决方案2】:

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

    1. 从 API 加载数据时,创建 mDbLiveData、中介 livedata mFinalLiveData 和布尔 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);
    });
    
    

    【讨论】:

    • 直播数据正在由另一个 SDK 返回。我没有关于何时调用 API 的信息。
    【解决方案3】:

    这篇文章有帮助。 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 }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-02-04
      • 1970-01-01
      • 1970-01-01
      • 2018-05-10
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多