Kotlin Flow 中的运算符重载任务

Posted 小陈乱敲代码

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Kotlin Flow 中的运算符重载任务相关的知识,希望对你有一定的参考价值。

当我们讨论在Kotlin Flow中使用运算符重载任务时,我们将讨论以下两个运算符:

retryWhen
retry
这两种运算符在大多数情况下都可以互换使用,今天我们将学习它们。

retryWhen

fun <T> Flow<T>.retryWhen(predicate: suspend FlowCollector<T>.(cause: Throwable, attempt: Long) -> Boolean): Flow<T>

并且,我们使用如下运算符:

.retryWhen  cause, attempt ->


这里,我们有两个参数,如下所示:

原因:这个cause是可抛出它是所有错误和异常的基类。
尝试:这个attempt表示当前尝试的数字。它从零 。
例如,如果启动任务时出现异常,我们将收到原因(异常)和尝试(0)。

这个retryWhen需要一个谓语函数来决定是否重试。

如果predicate函数返回是的,则只有它会重试,否则它不会。

例如,我们可以这样做:

.retryWhen  cause, attempt ->
    if (cause is IOException && attempt < 3) 
        delay(2000)
        return@retryWhen true
     else 
        return@retryWhen false
    

在这种情况下,我们回来了true当原因是IO异常,以及attempt计数小于3 .

因此,只有满足条件时才会重试。

注意:作为predicate函数是挂起函数,可以从中调用另一个挂起函数。

如果我们注意到上面的代码,我们已经调用delay(2000),以便仅在延迟后重试2秒。

retry

fun <T> Flow<T>.retry(
    retries: Long = Long.MAX_VALUE,
    predicate: suspend (cause: Throwable) -> Boolean =  true 
): Flow<T>

来自Kotlin流源代码的完整块。

fun <T> Flow<T>.retry(
    retries: Long = Long.MAX_VALUE,
    predicate: suspend (cause: Throwable) -> Boolean =  true 
): Flow<T> 
    require(retries > 0)  "Expected positive amount of retries, but had $retries" 
    return retryWhen  cause, attempt -> attempt < retries && predicate(cause) 

如果我们看到retry函数,它实际上调用重述时间内部。

retry函数具有默认参数。

如果我们不通过retries,它将使用Long.MAX_值 .
如果我们不通过predicate,它将提供真实的。
例如,我们可以这样做:

.retry()

它将继续重试,直到任务成功完成。

例如,我们也可以这样做:

.retry(3)

它只会重试3。

例如,我们也可以这样做:

.retry(retries = 3)  cause ->
    if (cause is IOException) 
        delay(2000)
        return@retry true
     else 
        return@retry false
    

在这里,它变得非常类似于我们使用retryWhen以上。

我们回来了true当原因是IOException。因此,只有当原因是IOException .

如果我们注意到上面的代码,我们已经调用delay(2000),因此仅在延迟2秒后重试。

现在,让我们看看代码示例。

这是一个函数,用于模拟长时间运行的异常任务。

private fun doLongRunningTask(): Flow<Int> 
    return flow 
        // your code for doing a long running task
        // Added delay, random number, and exception to simulate
        delay(2000)
        val randomNumber = (0..2).random()
        if (randomNumber == 0) 
            throw IOException()
         else if (randomNumber == 1) 
            throw IndexOutOfBoundsException()
        
        delay(2000)
        emit(0)
    

现在,当使用retry操作

viewModelScope.launch 
    doLongRunningTask()
        .flowOn(Dispatchers.Default)
        .retry(retries = 3)  cause ->
            if (cause is IOException) 
                delay(2000)
                return@retry true
             else 
                return@retry false
            
        
        .catch 
           // error
        
        .collect 
            // success
        

同样,当使用retryWhen操作

viewModelScope.launch 
    doLongRunningTask()
        .flowOn(Dispatchers.Default)
        .retryWhen  cause, attempt ->
            if (cause is IOException && attempt < 3) 
                delay(2000)
                return@retryWhen true
             else 
                return@retryWhen false
            
        
        .catch 
            // error
        
        .collect 
            // success
        

如果我们看到,每次我们加上延迟2秒,但在实际的用例中,我们添加了指数退避的延迟。别担心,我们也会执行的。

具有指数退避延迟的重试算子

viewModelScope.launch 
    var currentDelay = 1000L
    val delayFactor = 2
    doLongRunningTask()
        .flowOn(Dispatchers.Default)
        .retry(retries = 3)  cause ->
            if (cause is IOException) 
                delay(currentDelay)
                currentDelay = (currentDelay * delayFactor)
                return@retry true
             else 
                return@retry false
            
        
        .catch 
            // error
        
        .collect 
            // success
        

在这里,我们创建了两个变量:

电流延迟:这表示要在当前重试中使用的延迟。
延迟因子:我们用这个delayFactor把它乘以电流延迟增加下一次重试的延迟。
就这样,我们实现了具有指数退避延迟的重试。

您可以构建、运行和播放所提供项目中的所有示例。

这样我们就可以使用retry和重述时间解决android应用开发中的有趣问题。请记住,在大多数我们在Android应用程序开发中解决的情况下,两者都可以互换使用。

以上是关于Kotlin Flow 中的运算符重载任务的主要内容,如果未能解决你的问题,请参考以下文章

Kotlin + Flow 实现的 Android 应用初始化任务启动库

Kotlin——最详细的操作符与操作符重载详解(上)

Kotlin 扩展函数和运算符重载[第一行代码 Kotlin 学习笔记]

Kotlin中复合赋值(+=,-=,……)运算符重载

Kotlin 协程Flow 流异常处理 ( 收集元素异常处理 | 使用 try...catch 代码块捕获处理异常 | 发射元素时异常处理 | 使用 Flow#catch 函数捕获处理异常 )

Kotlin 协程Flow 流异常处理 ( 收集元素异常处理 | 使用 try...catch 代码块捕获处理异常 | 发射元素时异常处理 | 使用 Flow#catch 函数捕获处理异常 )