asc*_*sco 2 android coroutine kotlin kotlin-coroutines
考虑这个用例:
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>
}
Run Code Online (Sandbox Code Playgroud)
我从两个不同的来源获取数据并将它们组合起来。现在,这是连续运行的。当我想并行运行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))
}
Run Code Online (Sandbox Code Playgroud)
不鼓励使用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())
}
Run Code Online (Sandbox Code Playgroud)
或者这里理想的解决方案是什么?用例应该返回 aDeferred并让调用者await返回它吗?
不要将其传递scope给您,UseCase因为您会崩溃Clean Architecture。相反,只需将您的功能保留为Suspend. 如果您希望函数成为concurrent,只需将它们包装在async块中即可。
UseCase在您的中使用ViewModel并使用ViewModelScope来调用该suspend函数。
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))
}
}
Run Code Online (Sandbox Code Playgroud)
正如所提到的async需要一个范围,一个好的解决方案是创建一个简单的,CoroutineScope其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()}
}
.
.
.
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1650 次 |
| 最近记录: |