作者热门文章
- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
考虑这个用例:
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/
我是一名优秀的程序员,十分优秀!