【问题标题】:Kotlin flow network bound resource usage with force refresh and repeating errors强制刷新和重复错误的 Kotlin 流网络绑定资源使用
【发布时间】:2022-08-21 15:01:06
【问题描述】:

我是 Android/Kotlin 的新手,我正在制作一个应用程序,它使用 Room 缓存从网络加载不同的数据,并决定使用“网络绑定资源”算法(简称 NBR),可以简化为:

inline fun <ResultType, RequestType> networkBoundResource(
    crossinline query: () -> Flow<ResultType>,
    crossinline fetch: suspend () -> RequestType,
    crossinline saveFetchResult: suspend (RequestType) -> Unit,
    crossinline shouldFetch: (ResultType) -> Boolean = { true }
) = flow {
    val data = query().first()

    val flow = if (shouldFetch(data)) {
        emit(Resource.Loading(data))

        try {
            saveFetchResult(fetch())
            query().map { Resource.Success(it) }
        } catch (throwable: Throwable) {
            query().map { Resource.Error(throwable, it) }
        }
    } else {
        query().map { Resource.Success(it) }
    }

    emitAll(flow)
}

这是来自 Coding in Flow 的确切示例,非常类似于 Google 的 Github 浏览器实现与 LiveData 以及我见过的更多示例。 Resource 类是一个简单的状态+数据持有者,如下所示:

sealed class Resource<out R> {
    class Success<out T>(val data: T) : Resource<T>()
    class Error<out T>(val exception: Throwable, val data: T? = null) : Resource<T>()
    class Loading<out T>(val data: T? = null) : Resource<T>()
}

但是在我的存储库类中实现这个之后,我发现了一些我无法在任何地方找到解决方案的问题:

  1. 如何强制刷新数据?我创建了一个单独的函数,它重用 fetchsaveFetchResult 实现将数据从网络放入数据库,但我需要从 NBR 流收集器和挂起刷新函数刷新 UI 加载指示器,因为 NBR 永远不会为我重新发出加载状态。它有效,但感觉很糟糕。

  2. 在 NBR 中出错时,它会发出将任何 DB 更新值转换为 Resource.Error 的流,即使是在成功刷新后出现的值,这会导致在 UI 中重复相同的错误消息,即使刷新时一切都很好。

  3. 当这个 NBR 被多个用例重用时,如何防止被多次提取?我是否需要整个功能的互斥锁?

    标签: android kotlin kotlin-flow


    【解决方案1】:

    我认为将刷新场景分开不是一个好主意,我认为最好在 ViewModel 中使用以下模式来帮助您解决问题。

    @HiltViewModel
    class YourViewModel @Inject constructor(
        private val repository: YourRepository
    ) : ViewModel() {
    
    private val _result = MutableStateFlow<Resource<String>?>(null)
    val result = _result.asStateFlow()
    
    private var fetchJob: Job? = null
    fun getData() {
        fetchJob?.cancel()
        fetchJob = viewModelScope.launch {
            repository.getData().cancellable().collect{
                _result.emit(it)
            }
        }
      }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-20
      • 1970-01-01
      • 2021-11-11
      • 2019-09-15
      • 2011-08-06
      相关资源
      最近更新 更多