何时在 kotlin 中一起使用挂起函数和 Flow 或单独使用?

New*_*zal 7 suspend kotlin kotlin-flow

在审查用 kotlin 编写的一些代码时,有件事引起了我的注意。我在一些项目中查看领域层,在一些项目中,我看到挂起功能和 Flow 一起使用,而在一些项目中,我看到只使用 Flow。

例如暂停和流动在一起

class FetchMovieDetailFlowUseCase @Inject constructor(
    private val repository: MovieRepository
) : FlowUseCase<FetchMovieDetailFlowUseCase.Params, State<MovieDetailUiModel>>() {

    data class Params(val id: Long)

    override suspend fun execute(params: Params): Flow<State<MovieDetailUiModel>> =
        repository.fetchMovieDetailFlow(params.id)
}
Run Code Online (Sandbox Code Playgroud)

只是流动

class GetCoinUseCase @Inject constructor(
    private val repository: CoinRepository
){
 
    operator fun invoke(coinId:String): Flow<Resource<CoinDetail>> = flow {

        try {
            emit(Resource.Loading())
            emit(Resource.Success(coin))

        }catch (e:HttpException){
            emit(Resource.Error(e.localizedMessage ?: "An unexpected error occured"))
        }catch (e:IOException){
            emit(Resource.Error("Couldn't reach server. Check your internet connection."))
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

只是暂停

class GetLatestNewsWithAuthorsUseCase(
  private val newsRepository: NewsRepository,
  private val authorsRepository: AuthorsRepository,
  private val defaultDispatcher: CoroutineDispatcher = Dispatchers.Default
) {
    suspend operator fun invoke(): List<ArticleWithAuthor> =
        withContext(defaultDispatcher) {
            val news = newsRepository.fetchLatestNews()
            val result: MutableList<ArticleWithAuthor> = mutableListOf()
            // This is not parallelized, the use case is linearly slow.
            for (article in news) {
                // The repository exposes suspend functions
                val author = authorsRepository.getAuthor(article.authorId)
                result.add(ArticleWithAuthor(article, author))
            }
            result
        }
}
Run Code Online (Sandbox Code Playgroud)

这三个都是不同的项目,不要被代码所困扰,这些只是我遇到过的项目,我分享是为了展示示例,但我想在这里提请您注意的是,有时只有暂停使用function,有时只使用Flow,有时两者都使用。这是什么原因呢?你能详细解释一下吗?我试图将其纳入我的逻辑

Ten*_*r04 12

suspend函数对于以暂停、同步的方式检索单个项目是有意义的。

当您决定开始收集时,流程会随着时间的推移返回多个项目。它们通常用于监视随时间变化的事物,以检索事物的最新值。例如,每次数据库中的某些内容发生更改时,来自数据库的流都可以发出新值。

使用检索 Flow 的挂起函数将两者结合起来几乎没有意义。这是因为 Flow 本身是一个轻量级对象,通常不需要任何前期、耗时的工作来检索和创建。

避免在返回流时创建函数的原因suspend是它使用起来更加麻烦。在某些情况下,您可能希望传递流而不收集它,并且您不希望仅仅为了获取流而启动协程。或者,您可能只想使用这种漂亮、简洁的语法来创建专用的集合协程:

someUseCase.retrieveSomeFlow()
    .onEach { ... }
    .launchIn(someScope)
Run Code Online (Sandbox Code Playgroud)

代替:

someScope.launch {
    someUseCase.retrieveSomeFlow().collect {
        ...
    }
}
Run Code Online (Sandbox Code Playgroud)

如果您必须检索某些内容作为流程基础的密钥,则可能会出现例外情况。例如,从 API 检索用户 ID,然后返回使用该用户 ID 来获取流的项目的流。但即使这样通常也是不必要的,因为您可以将该 ID 检索放入流程中。例如:

fun getUserItems(): Flow<UserItem> = flow {
    val userId = someAPI.retrieveUserId() // calling a suspend function
    emitAll(someAPI.getUserItemsFlow(userId))
}
Run Code Online (Sandbox Code Playgroud)

这样做的唯一缺点是,如果您多次收集流量,则每次开始收集时都必须重新检索用户 ID。