如何在Interactor UseCase中获得CoroutineScope?

问题描述 投票:0回答:1

考虑这个用例。

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 是不鼓励的,因为当调用者的生命周期结束时,该作业不会被取消。

由于我的usecase不知道调用者的生命周期,它应该使用哪个作用域?将作用域传递给usecase是一个可以接受的解决方案吗?

   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())
    }

或者这里最理想的解决方案是什么?usecase应该返回一个 Deferred 并让来电者 await 它?

android kotlin coroutine kotlin-coroutines
1个回答
3
投票

不要传递 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))
    }
}

编辑

如前所述 async 需要一个范围,一个好的解决方案是创建一个简单的 CoroutineScopeUseCase 其工作是对这个单一的coroutine进行作用域,以运行这两个 async 同时进行的任务。

val customScope = CoroutineScope(Dispatchers.Main)

override suspend fun getPhotos(): List<Photo> {
    customScope.launch {
        val photos = async { photosRepository.getPhotos() }
        val favoriteIds = async { favoritesRepository.getFavoriteIds()}
    }
    .
    .
    .
}
© www.soinside.com 2019 - 2024. All rights reserved.