我看到 Flow 有一个 retry 机制,但我的用例与我在文档中看到的有所不同,我有一个片段,其中包含打开此片段时从 API 填充的列表,但 API 调用可能会失败并以任何原因抛出异常,在这种情况下,我想显示一个在单击时再次调用 API 的按钮,如下所示:
存储库
fun getData(): Flow<Result<T>> = service.getData()
视图模型
val data: Flow<Result<T>> = repo.getData()
碎片
viewModel.data.collect{ result ->
if(result is Error){
showRetryButton() // Show the retry button on failed API
}
....
}
retryButton.setOnClickListener{
// do something to retry the API call
}
Flow 重试 可以帮助我吗?如果没有,您认为再次调用失败的 API 的最佳方法是什么?
提前致谢:)
// Actual implementation of retry
fun Flow<Int>.retry(
retries: Long = Long.MAX_VALUE,
predicate: suspend (cause: Throwable) -> Boolean = {true}
): Flow<Int> {
require(retries > 0) {
"Expected positive amount of retries, but had $retries"
}
return retryWhen { cause, attempt ->
attempt < retries && predicate(cause)
}
}
fun Flow<Int>.retryWhen(
predicate: suspend FlowCollector<Int>.(
cause: Throwable,
attempt: Long,
) -> Boolean,
): Flow<Int> = flow {
var attempt = 0L
do {
val shallRetry = try {
collect {
// get value from flow if it is exception(API fail) then it caught by catch block
emit(it)
}
println("return false") // it will only return false if there is no exception in emitted values of flow
false
} catch (e: Throwable) {
// API fail catch
// show retry button // if user press then attempt remain same as 1 we again retry
// otherwise attempt = 2 greater than our retries .
println("cause block")
predicate(e, attempt++) // we check if exception can be ignore and attempt < retries
.also {
if (!it) //if attempt > retries --> throw exception that we caught in collect // app crash
{
// throw e // you can ignore it so app do not crash // like show dialog box , toast etc so user see it can not retry
}
//else // again retry
}
}
} while (shallRetry)
}
fun interface FlowCollector<Int>{
suspend fun emit(value : Int)
}
interface Flow<Int>{
suspend fun collect(collector : FlowCollector<Int>)
}
fun flow(builder : suspend FlowCollector<Int>.() -> Unit): Flow<Int> = object : Flow<Int>{
override suspend fun collect(collector : FlowCollector<Int>){
collector.builder()
}
}
suspend fun main(){
flow {
emit(1)
emit(2)
error("API fail")
emit(3)
}.retry(1) {
print(it.message)
true
}.collect { print(it) }
}