Android 有进展的干净体系结构用例[无RxJava]

Android 有进展的干净体系结构用例[无RxJava],android,kotlin,kotlin-coroutines,clean-architecture,Android,Kotlin,Kotlin Coroutines,Clean Architecture,我在试图找出实现用例的最佳方法时遇到了一个问题。我见过这样的例子: 谷歌I/O安卓应用程序 我不喜欢的是: 您将在UI中接收结果并在那里做出许多决策 无进展 我认为这是对上述内容的升级: Android架构蓝图 他们正在使用协同程序,现在结果出现在ViewModel中,而且效果要好得多。但同样:没有进展 我这里的问题是每个人都在使用RxJava,因为其他人都在使用它。我看到很多人认为这是“在后台执行任务”的东西。但这对我来说太过分了。我不需要它 我已经看到了一些关于协同程序频道的例子,但

我在试图找出实现用例的最佳方法时遇到了一个问题。我见过这样的例子:

谷歌I/O安卓应用程序

我不喜欢的是:

  • 您将在UI中接收结果并在那里做出许多决策
  • 无进展
我认为这是对上述内容的升级:

Android架构蓝图

他们正在使用协同程序,现在结果出现在ViewModel中,而且效果要好得多。但同样:没有进展

我这里的问题是每个人都在使用RxJava,因为其他人都在使用它。我看到很多人认为这是“在后台执行任务”的东西。但这对我来说太过分了。我不需要它

我已经看到了一些关于协同程序频道的例子,但是它们真的很难看

最近我偶然发现了Roman Elizarov的这篇文章:

我是这样做的:

class ProduceValueWithProgressUseCase @Inject constructor(
    private val executor: Executor
) {

    operator fun invoke(): Flow<Result<Int, Int>> {
        return callbackFlow {
            val callback = object : CallbackProgress {
                override fun onProgress(result: Int) {
                    offer(Result.Loading(result))
                }

                override fun onSuccess(result: Int) {
                    offer(Result.Success(result))
                    close()
                }

                override fun onError(e: Exception) {
                    offer(Result.Error(e))
                    close()
                }

            }

            val producer = ValueWithProgressProducer(callback)
            executor.execute(producer)
            awaitClose {}
        }
    }

}
是的,基本上Flows API将为我完成这项工作。我甚至创建了一个小应用程序来测试itm,在那里我只生成数字,效果很好。我不喜欢的是:

  • 太多的实验常规SAPI注释必须到位。例如这里(很抱歉格式化):

    @抑制(“无内容到内联”) @实验常规 公共内联fun callbackFlow(@builderReference noinline块:挂起 生产范围(->单位):流量= 渠流(块)

上述代码是文件kotlinx.coroutines.flow.Builders.kt的一部分,该文件的版本为:kotlinx-coroutines-core-1.3.2

  • 在某些时候,我用@Preview注释找到了一些东西。(老实说,我不记得在哪里了。我已经删除了一些东西。)
  • 我也试了一下,看看测试将如何进行,但这并不简单。您可以在Blueprinst的代码中看到相同的内容
  • 我还混合了执行任务的代码和任务本身。我的意思是使用callbackFlow()

所以最后我看到了一些东西,看起来像是在尖叫着要在明年改变。因此,请给出您的想法。

因此,我将根据您在问题描述中提出的内容向您展示一个实现,请随时提出更多问题,甚至提出改进建议

当前的实现基于Kotlin Coroutines 1.3.2的稳定版本

回调接口

interface CallbackProgress {
    suspend fun onProgress(result: Int)
    suspend fun onSuccess(result: Int)
    suspend fun onError(exception: Exception)
}
制作人 迭代并执行回调函数的某些方法。试着模仿你的

class Producer(private val callback: CallbackProgress) {
    suspend fun execute(fail: Boolean) {
        (0 until 10).forEach {
            when {
                it < 9 -> callback.onProgress(it)
                fail -> callback.onError(InterruptedException("blabla"))
                else -> callback.onSuccess(it)
            }
            delay(500)
        }
    }
}
互动者 在这里您需要小心,因为排放应该在同一个协同程序中完成,否则您将需要使用非稳定API,例如

为了测试以上内容,我编写了以下内容,其中演示了故障和非故障排放

fun main() = runBlocking {
    val useCase = UseCase()
    useCase(true).collect {
        when (it) {
            is State.Loading -> println("State for failure [Loading -> ${it.progress}]")
            is State.Success -> println("State for failure [Success -> ${it.value}]")
            is State.Error -> println("State for failure [Error -> ${it.exception.message}]")
        }
    }
    useCase(false).collect {
        when (it) {
            is State.Loading -> println("State  without failure [Loading -> ${it.progress}]")
            is State.Success -> println("State without failure [Success -> ${it.value}]")
            is State.Error -> println("State without failure [Error -> ${it.exception.message}]")
        }
    }
}
输出

State for failure [Loading -> 1]
State for failure [Loading -> 2]
State for failure [Loading -> 3]
State for failure [Loading -> 4]
State for failure [Loading -> 5]
State for failure [Loading -> 6]
State for failure [Loading -> 7]
State for failure [Loading -> 8]
State for failure [Error -> blabla]

-------------------------------------

State  without failure [Loading -> 0]
State  without failure [Loading -> 1]
State  without failure [Loading -> 2]
State  without failure [Loading -> 3]
State  without failure [Loading -> 4]
State  without failure [Loading -> 5]
State  without failure [Loading -> 6]
State  without failure [Loading -> 7]
State  without failure [Loading -> 8]
State without failure [Success -> 9]

你能发布一些代码片段吗?自2019年8月以来,流量一直稳定。一些转换运算符和终端运算符处于实验和预览阶段,我很确定您不必使用它们就可以实现您想要的结果。@Giorgosnokleus,给您。
callbackFlow
确实不稳定。但是如果你检查一下稳定的API,我很确定你可以实现你想要的,而不需要
callbackFlow
,而是普通的
Flow
s。不幸的是,我没有在我的机器上玩一个例子,我留下了一个粗略的实现,希望能有所帮助!
class UseCase {
    operator fun invoke(fail: Boolean) = flow {
        val callback = object : CallbackProgress {
            override suspend fun onSuccess(result: Int) {
                withContext(coroutineContext) { emit(State.Success(result)) }
            }

            override suspend fun onError(exception: Exception) {
                withContext(coroutineContext) { emit(State.Error(exception)) }
            }

            override suspend fun onProgress(result: Int) {
                withContext(coroutineContext) { emit(State.Loading(result)) }
            }
        }

        Producer(callback).execute(fail)
    }
}
fun main() = runBlocking {
    val useCase = UseCase()
    useCase(true).collect {
        when (it) {
            is State.Loading -> println("State for failure [Loading -> ${it.progress}]")
            is State.Success -> println("State for failure [Success -> ${it.value}]")
            is State.Error -> println("State for failure [Error -> ${it.exception.message}]")
        }
    }
    useCase(false).collect {
        when (it) {
            is State.Loading -> println("State  without failure [Loading -> ${it.progress}]")
            is State.Success -> println("State without failure [Success -> ${it.value}]")
            is State.Error -> println("State without failure [Error -> ${it.exception.message}]")
        }
    }
}
State for failure [Loading -> 1]
State for failure [Loading -> 2]
State for failure [Loading -> 3]
State for failure [Loading -> 4]
State for failure [Loading -> 5]
State for failure [Loading -> 6]
State for failure [Loading -> 7]
State for failure [Loading -> 8]
State for failure [Error -> blabla]

-------------------------------------

State  without failure [Loading -> 0]
State  without failure [Loading -> 1]
State  without failure [Loading -> 2]
State  without failure [Loading -> 3]
State  without failure [Loading -> 4]
State  without failure [Loading -> 5]
State  without failure [Loading -> 6]
State  without failure [Loading -> 7]
State  without failure [Loading -> 8]
State without failure [Success -> 9]