Правильная реализация обработки ошибок Retrofit android
Возник довольно интересный вопрос - правильно ли реализована мной обработка ошибок в моем клиент-серверном приложении. Вот как реализовано в моем синглтоне для обращения к интерфейсу:
fun apiService(): APIService {
val interceptor = HttpLoggingInterceptor()
interceptor.level = HttpLoggingInterceptor.Level.BODY
val disp = Dispatcher()
disp.maxRequests = 1
val client = OkHttpClient.Builder()
.addInterceptor(interceptor)
.connectTimeout(100, TimeUnit.SECONDS)
.dispatcher(disp)
.readTimeout(100, TimeUnit.SECONDS).build()
client.dispatcher.cancelAll()
val retrofit = Retrofit.Builder()
.baseUrl(BuildConfig.API_URL)
.client(client)
.addConverterFactory(GsonConverterFactory.create())
.build()
return retrofit.create(APIService::class.java)
}
и теперь как реализовано в запросе обработка ошибок:
fun archiveNote(id: Int?, context: Context) {
apiService().archiveNote("Bearer " + context.getSharedPreferences("app_data", 0).getString("access_token", ""), id).enqueue(object : Callback<NoteAction> {
override fun onResponse(call: Call<NoteAction>, response: Response<NoteAction>) {
if (response.isSuccessful) {
} else {
if (response.code() == 500) {
Toast.makeText(context, context.getString(R.string.server_error_500), Toast.LENGTH_SHORT).show()
} else {
try {
val jObjError = JSONObject(Objects.requireNonNull<ResponseBody>(response.errorBody()).string())
error["message"] = jObjError.getString("message")
error["request_no"] = "20"
workingWithErrors(error, context)
} catch (e: Exception) {
//Toast.makeText(getContext(), e.getMessage(), Toast.LENGTH_LONG).show();
}
}
}
}
override fun onFailure(call: Call<NoteAction>, t: Throwable) {
}
})
}
и вот бывают ситуации когда запрос на обновление токена идет, то может быть послано 5 например запросов для обновление токена, а это неправильно. Поэтому задался вопросом правильно ли то что я обрабатываю результат запроса в теле метода, а именно:
if (response.isSuccessful) {
} else {
}
Может есть какие-то практики которые делают процесс обработки ошибок более совершенным и правильным. Приведенный выше вариант реализации мне кажется является наиболее встречаемым и популярным.
вот как я отлавливаю момент протухания токена:
sp.getLong("expires_in", 0) - sp.getLong("time_delta", 0) - System.currentTimeMillis() / 1000 <= 60
то есть если это условие выполняется то шлем запрос на обновление токена, либо шлем запрос какой нужно.
Ответы (1 шт):
Ну понятия правильно тут наверное нет. Все зависит от того как и где вы хотите обрабатывать ошибки.
Есть несколько вариантов обработки ошибок. 1. Обрабатывать их непосредственно в месте возникновения. Т.е. как только вы ее получили в вашем классе, отвечающим, за запросы в сеть там же и обработали. В таком случае вы будете точно знать где возникла ошибка. Если, к примеру, вы хотите просто залогировать ошибку или выполнить действия и никак не оповещать пользователя, это хорошее решение. 2. Вариант пробрасывать эту ошибку в сущности которые непосредственно взаимодействуют с пользователем. В таком случае вам будет труднее отследить место возникновения этой ошибки, но вы сможете обработать ее на уровне UI (например показать пользователю уведомление или какой-то другой экран). Тут есть пару походов.
Первый, это просто пробросить ее по стеку вызовов вверх. И там просто отреагировать. Второй, который мне нравится больше - обернуть ошибку в какое-то состояние и вернуть это состояние вызывающему объекту.
Вот тут вы можете просмотреть мою реализацию второго подхода