Reputation: 4964
Suppose I have the following UseCase to fetch users as a flow
class FetchUsersFlowUseCase(
private val userRepository: UserRepository
) {
operator fun invoke(): Flow<List<User>> {
return userRepository.fetchUsersFlow()
}
}
And a Repository with a function that fetches users as a Flow. When that function is called, an attempt to sync the local database (which is the Single Source of Truth) is also executed.
class UserRepositoryImpl(
private val localUserDataSource: LocalUserDatasource,
private val remoteUserDataSource: RemoteUserDatasource,
private val coroutineScope: CoroutineScope
) : UserRepository {
override fun fetchUsersFlow(): Flow<List<User>> {
coroutineScope.launch {
val remoteUsersResult = remoteUserDataSource.fetchUsers()
if (remoteUsersResult.isSuccess) {
// Success: update users locally
} else {
// What to do?
// How to correctly notify who observes that something wrong happened?
}
}
return localUserDataSource.fetchUsersFlow()
}
}
But if something unexpected happens (example: no Internet connection), how can I correctly notify who observes the Flow?
Upvotes: 0
Views: 242
Reputation:
Wrap your result in an object, so consumers can determine success:
sealed interface Result {
object Error: Result
data class Success(val value: List<User>)
}
and
override fun fetchUsersFlow(): Flow<Result> {
coroutineScope.launch {
val remoteUsersResult = remoteUserDataSource.fetchUsers()
if (remoteUsersResult.isSuccess) {
yourFlow.emit(Result.Success(remoteUsersResult))
} else {
yourFlow.emit(Result.Error)
}
}
return localUserDataSource.fetchUsersFlow()
}
Then on the consumer side, you can
when(valueFromFlow) {
Result.Error -> // handle it
is Result.Success -> it.value // is your List<User>
}
You can add even more Result
implementations to signal other cases, or make Error
a data class too and give it fields holding details.
Upvotes: 0