Последние пару месяцев я боролся с паттернами MVVM и компонентами android-архитектура-компонентов.
В моем последнем проекте, хотя я пытался отделить часть логики приложения, но это закончилось большим количеством беспорядка кода. Каждый фрагмент проделал большую работу, от обработки пользовательского интерфейса до обработки сетевых запросов и ...
В этом новом приложении я следовал рекомендациям по архитектуре приложений для Android, и до сих пор все идет хорошо. Но дело в том, что я не знаю, как обрабатывать сетевые ошибки, и я не понимаю, как я должен уведомлять пользователя, если некоторые сетевые вызовы не выполняются.
После поиска и прочтения некоторых сообщений в блоге я получил следующие функции кода (SafeApiCall и SafeApiResutl) для обработки сетевых запросов в одном месте, но дело в том, что все мои сетевые запросы выполняются с использованием модернизации и класса NetworkDataSource. Затем Я передаю NetworkDataSource и Dao классу RepositoryImpl, который является реализацией моего интерфейса репозитория. затем я передаю репозиторий в viewModel, так что ViewModel ничего не знает о сети, дао или о чем-либо еще. Итак, вот проблема, как я могу уведомить пользователя в случае каких-либо сетевых ошибок? Я думал о создании LiveData <> и передаче ему ошибок на сетевом уровне, но в этом случае репозиторий должен соблюдать это, а также, скажем, создать LiveData в репозитории, чтобы viewModel наблюдал это и так далее ... Но это слишком много цепочки, мне не нравится идея сделать это. Я также взглянул на проект GoogleSamples Todo-MVVM-live-kotlin, но, честно говоря, я не понял, что происходит.
suspend fun <T : Any> safeApiCall(call: suspend () -> Response<BasicResponse<T>>, errorMessage: String): T? {
return when (val result = safeApiResult(call)) {
is NetworkResult.Success -> {
Timber.tag("safeApiCall").d("data is ${result.serverResponse.data}")
result.serverResponse.data
}
is NetworkResult.Error -> {
Timber.tag("SafeApiCall").e("$errorMessage & Exception - ${result.exception}")
null
}
else -> TODO()
}
}
private suspend fun <T : Any> safeApiResult(
call: suspend () -> Response<BasicResponse<T>>
): NetworkResult<T> {
return try {
val response = call.invoke()
Timber.tag("SafeApiResult")
.d("response code : ${response.code()}, server value : ${response.body()!!.status}, server message: ${response.body()!!.message}")
if (response.isSuccessful) {
return when (ServerResponseStatus.fromValue(response.body()!!.status)) {
ServerResponseStatus.SUCCESS -> NetworkResult.Success(response.body()!!)
ServerResponseStatus.FAILED -> TODO()
ServerResponseStatus.UNKNOWN -> TODO()
}
} else {
TODO()
}
} catch (exception: Exception) {
Timber.tag("SafeApiResultFailed").e(exception)
NetworkResult.Error(exception)
}
}
sealed class NetworkResult<out T : Any> {
data class Success<out T : Any>(val serverResponse: BasicResponse<out T>) : NetworkResult<T>()
data class Error(val exception: Exception) : NetworkResult<Nothing>()
}