如何在suspend函数中等待Flow执行完成后返回组装好的对象
解决方案
核心问题说明
你当前的代码无法返回的核心原因取决于transactionRepository.getAll返回的Flow类型:
- 如果是有限流(发射固定数量值后主动结束):
collect会挂起直到Flow执行完毕,你只需要在collect代码块后直接返回account即可。 - 如果是无限流(最常见的场景,比如Room返回的数据库可观察流,会持续监听数据变化永远不会主动结束):
collect会永久挂起,后续代码永远不会执行,这种情况需要调整实现方案。
场景1:只需获取一次当前最新数据(最常用)
使用first()终端操作符,拿到Flow发射的第一个值后立即终止收集,不会持续挂起:
override suspend fun getAccount(accountId: Int): Account { val account = Account(accountRepository.get(accountId)) // 只取第一个发射的事务列表 val transactions = transactionRepository.getAll(accountId) .mapIterable { val transaction = Transaction(it) val category = Category(categoryRepository.get(it.categoryId)) transaction.category = category transaction.account = account return@mapIterable transaction }.first() account.transactions = transactions return account }
场景2:Flow为有限流,需要等待所有发射完成
直接在collect后返回即可,collect会自动挂起直到Flow执行完毕:
override suspend fun getAccount(accountId: Int): Account { val account = Account(accountRepository.get(accountId)) transactionRepository.getAll(accountId).mapIterable { val transaction = Transaction(it) val category = Category(categoryRepository.get(it.categoryId)) transaction.category = category transaction.account = account return@mapIterable transaction }.collect { account.transactions = it } // Flow执行完成后会走到这里 return account }
场景3:需要持续监听数据变化返回最新的Account
这种场景不应该用suspend函数返回单个对象,直接将返回值改为Flow
override fun getAccount(accountId: Int): Flow<Account> { return flow { val baseAccount = Account(accountRepository.get(accountId)) transactionRepository.getAll(accountId) .mapIterable { val transaction = Transaction(it) val category = Category(categoryRepository.get(it.categoryId)) transaction.category = category transaction.account = baseAccount return@mapIterable transaction }.collect { transactions -> baseAccount.transactions = transactions emit(baseAccount) } } }
内容的提问来源于stack exchange,提问作者DennisVA
相关产品推荐
相关产品推荐

