我是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)
}
这是《流中编码》中的确切示例,非常模拟谷歌的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>()
}
但在我的存储库类中实现了这一点后,我发现了一些在任何地方都找不到解决方案的问题:
如何强制刷新数据?我已经制作了一个单独的函数,它重用
fetch
和saveFetchResult
实现将网络中的数据放入DB,但我需要刷新NBR流收集器和挂起刷新函数中的UI加载指示符,因为NBR永远不会为我重新发出加载状态。它可以工作,但感觉不好。在NBR中出现错误时,它会发出将任何DB更新值转换为
Resource.Error
的流,即使是在成功刷新后的值,这也会导致在UI中重复相同的错误消息,即使刷新时一切正常。当这个NBR被多个用例重复使用时,我如何防止被多次提取?整个函数需要互斥锁吗?
我认为分离刷新场景不是一个好主意,我认为最好在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)
}
}
}
}