如何对特定事件使用Flow重试功能?

问题描述 投票:0回答:1

我看到 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 的最佳方法是什么?

提前致谢:)

android kotlin mvvm kotlin-coroutines kotlin-flow
1个回答
0
投票
// 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) }
}
© www.soinside.com 2019 - 2024. All rights reserved.