考虑这个用例:
class GetPhotosUseCase(
private val photosRepository: IPhotosRepository,
private val favoritesRepository: IFavoritesRepository
) : IGetPhotosUseCase {
override suspend fun getPhotos(): List<Photo> {
val photos = photosRepository.getPhotos()
val favoriteIds = favoritesRepository.getFavoriteIds()
return photos.map {
it.copy(isFavorite = favoriteIds.contains(it.id))
}
}
}
interface IPhotosRepository {
suspend fun getPhotos(): List<Photo>
}
interface IFavoritesRepository {
suspend fun getFavoriteIds(): List<Int>
}
我从两个不同的来源获取数据并将它们组合起来。现在,这是连续运行的。
当我想并行运行 photosRepository.getPhotos()
和 favoritesRepository.getFavoriteIds()
以节省执行时间时,我的幼稚方法是:
override suspend fun getPhotos(): List<Photo> {
val photosDeferred = GlobalScope.async { photosRepository.getPhotos() }
val favoriteIdsDeferred = GlobalScope.async { favoritesRepository.getFavoriteIds() }
return applyFavoritesToPhotos(photosDeferred.await(), favoriteIdsDeferred.await())
}
private fun applyFavoritesToPhotos(photos: List<Photo>, favoriteIds: List<Int>) = photos.map {
it.copy(isFavorite = favoriteIds.contains(it.id))
}
不鼓励使用GlobalScope
,因为当调用者的生命周期结束时,作业不会被取消。
由于我的用例不知道调用者的生命周期,它应该使用哪个范围? 将范围传递给用例是否是一个不错的解决方案,例如:
override suspend fun getPhotos(scope: CoroutineScope): List<Photo> {
val photosDeferred = scope.async { photosRepository.getPhotos() }
val favoriteIdsDeferred = scope.async { favoritesRepository.getFavoriteIds() }
return applyFavoritesToPhotos(photosDeferred.await(), favoriteIdsDeferred.await())
}
或者这里理想的解决方案是什么?用例是否应该返回一个Deferred
并让调用者await
它?
最佳答案
不要将范围
传递给您的UseCase
,因为您会破坏干净的架构
。相反,只需将您的函数保持为挂起
即可。如果您希望函数并发
,只需将它们包装在async
block 中。
在 ViewModel
中使用 UseCase
并使用 ViewModelScope
调用挂起
函数。
override suspend fun getPhotos(): List<Photo> {
val photos = async { photosRepository.getPhotos() }
val favoriteIds = async { favoritesRepository.getFavoriteIds() }
return photos.await().map {
it.copy(isFavorite = favoriteIds.await().contains(it.id))
}
}
编辑
正如前面提到的async
需要一个作用域,一个好的解决方案是在UseCase
其工作是确定将同时运行这两个 async
任务的单个协程的范围。
val customScope = CoroutineScope(Dispatchers.Main)
override suspend fun getPhotos(): List<Photo> {
customScope.launch {
val photos = async { photosRepository.getPhotos() }
val favoriteIds = async { favoritesRepository.getFavoriteIds()}
}
.
.
.
}
关于android - 如何在Interactor/UseCase中获取CoroutineScope,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61396762/