存储库模式中的 Kotlin Flow
Kotlin Flow in repository pattern
我想将 Flow 作为 return 类型用于我存储库中的所有函数。例如:
suspend fun create(item:T): Flow<Result<T>>
此函数应调用 2 个数据源:远程(在服务器上保存数据)和本地(在本地保存来自服务器的 returned 数据)。问题是我如何实现这个场景:
- 尝试使用 RemoteDataSource 保存数据
- 如果 1. 失败 - 尝试 N 次,超时 M
- 如果数据最终从服务器 returned - 在本地使用 LocalDataSource
- return 使用本地保存的数据流动
RemoteDataSource 和 LocalDataSource 都很有趣 create
具有相同的签名:
suspend fun create(item:T): Flow<Result<T>>
所以他们都是return数据流。如果您对如何实现它有任何想法,我将不胜感激。
------ 更新#1 ------
部分可能的解决方案:
suspend fun create(item:T): Flow<T> {
// save item remotely
return remoteDataSource.create(item)
// todo: call retry if fails
// save to local a merge two flows in one
.flatMapConcat { remoteData ->
localDataSource.create(remoteData)
}
.map {
// other mapping
}
}
这是一个可行的想法吗?
我认为你的想法是正确的,但你试图一次完成所有事情。
我发现最好(也很容易)的是:
来自本地数据源的公开数据流(使用 Room 很容易)
一个或多个公开的挂起函数,如create
或refresh
,对远程数据源进行操作并保存到本地(如果没有错误)
对于 ex 我有一个在我的项目中获取车辆的存储库(isCurrent
信息只是本地的,isLeft
/isRight
是因为我使用 Either
但是适用任何错误处理):
class VehicleRepositoryImpl(
private val localDataSource: LocalVehiclesDataSource,
private val remoteDataSource: RemoteVehiclesDataSource
) : VehicleRepository {
override val vehiclesFlow = localDataSource.vehicleListFlow
override val currentVehicleFlow = localDataSource.currentVehicleFLow
override suspend fun refresh() {
remoteDataSource.getVehicles()
.fold(
ifLeft = { /* handle errors, retry, ... */ },
ifRight = { reset(it) }
)
}
private suspend fun reset(vehicles: List<VehicleEntity>) {
val current = currentVehicleFlow.first()
localDataSource.reset(vehicles)
if (current != null) localDataSource.setCurrentVehicle(current)
}
override suspend fun setCurrentVehicle(vehicle: VehicleEntity) =
localDataSource.setCurrentVehicle(vehicle)
override suspend fun clear() = localDataSource.clear()
}
希望这对您有所帮助,您可以根据自己的情况进行调整:)
我想将 Flow 作为 return 类型用于我存储库中的所有函数。例如:
suspend fun create(item:T): Flow<Result<T>>
此函数应调用 2 个数据源:远程(在服务器上保存数据)和本地(在本地保存来自服务器的 returned 数据)。问题是我如何实现这个场景:
- 尝试使用 RemoteDataSource 保存数据
- 如果 1. 失败 - 尝试 N 次,超时 M
- 如果数据最终从服务器 returned - 在本地使用 LocalDataSource
- return 使用本地保存的数据流动
RemoteDataSource 和 LocalDataSource 都很有趣 create
具有相同的签名:
suspend fun create(item:T): Flow<Result<T>>
所以他们都是return数据流。如果您对如何实现它有任何想法,我将不胜感激。
------ 更新#1 ------
部分可能的解决方案:
suspend fun create(item:T): Flow<T> {
// save item remotely
return remoteDataSource.create(item)
// todo: call retry if fails
// save to local a merge two flows in one
.flatMapConcat { remoteData ->
localDataSource.create(remoteData)
}
.map {
// other mapping
}
}
这是一个可行的想法吗?
我认为你的想法是正确的,但你试图一次完成所有事情。
我发现最好(也很容易)的是:
来自本地数据源的公开数据流(使用 Room 很容易)
一个或多个公开的挂起函数,如
create
或refresh
,对远程数据源进行操作并保存到本地(如果没有错误)
对于 ex 我有一个在我的项目中获取车辆的存储库(isCurrent
信息只是本地的,isLeft
/isRight
是因为我使用 Either
但是适用任何错误处理):
class VehicleRepositoryImpl(
private val localDataSource: LocalVehiclesDataSource,
private val remoteDataSource: RemoteVehiclesDataSource
) : VehicleRepository {
override val vehiclesFlow = localDataSource.vehicleListFlow
override val currentVehicleFlow = localDataSource.currentVehicleFLow
override suspend fun refresh() {
remoteDataSource.getVehicles()
.fold(
ifLeft = { /* handle errors, retry, ... */ },
ifRight = { reset(it) }
)
}
private suspend fun reset(vehicles: List<VehicleEntity>) {
val current = currentVehicleFlow.first()
localDataSource.reset(vehicles)
if (current != null) localDataSource.setCurrentVehicle(current)
}
override suspend fun setCurrentVehicle(vehicle: VehicleEntity) =
localDataSource.setCurrentVehicle(vehicle)
override suspend fun clear() = localDataSource.clear()
}
希望这对您有所帮助,您可以根据自己的情况进行调整:)