Android: Offline-first repository, 2 data source. Как обрабатывать ошибки?
Всем привет!
Подскажите, пожалуйста, как правильно осуществлять обработку ошибок при получении в репозитории данных из двух data source:
Есть репозиторий, который должен при вызове метода getOrders() запросить обновление данных от бэка и сразу же вернуть данные имеющиеся в локальной БД, чтобы пользователь не ждал подгрузки данных. Не понимаю как отправлять ошибки, которые могут произойти при обращении к Network Data Source на UI слой?
Понятно, что можно сделать какой-нибудь класс-обёртку типа Result<T> c наследниками Success/Error, но не понимаю какой тогда должен быть возвращаемый тип у getOrders. С Result<T> уже не вернешь StateFlow, а если пытаюсь делать Flow и эмиттить сначала ошибку, а потом данные из локального репозитория, то получаю Flow exception - Emission from another coroutine is detected.
Или ошибки надо вообще на другом уровне обрабатывать?
Может кто поделиться примером как это надо обрабатывать и какие есть Best Practices на этот случай? Задача по сути проста: показать как можно быстрее пользователю данные из БД, загрузить свежие данные из сети, при этом в случае какой-либо ошибки показать юзеру Snackbar с сообщением об ошибке, не лишив его при этом, возможности работать с локальными данными.
@Singleton
class OrderRepositoryImpl @Inject constructor(
private val localDataSource: LocalDataSource,
private val networkDataSource: NetworkDataSource,
userRepository: UserRepository,
@DefaultDispatcher private val dispatcher: CoroutineDispatcher,
@ApplicationScope private val scope: CoroutineScope
) : OrderRepository {
override fun getOrders(forceUpdate: Boolean = false): StateFlow<List<Order>> {
val user = userStateFlow.value ?: throw IllegalStateException("Undefined user")
if (forceUpdate) {
scope.launch {
try {
val remoteOrders = networkDataSource.loadOrders()
localDataSource.updateOrders(remoteOrders)
} catch (e: Exception) {
//TODO:Прокинуть ошибку и показать на UI-слое
Log.d(
"OrderRepositoryImpl",
"getOrdersStream() error: ${e.localizedMessage}"
)
}
}
}
return localDataSource
.getOrders(user)
.stateIn(
scope = scope,
started = SharingStarted.Lazily,
initialValue = listOf()
)
}
}