Как организовать обработку успешных и неуспешных сетевых запросов
Что проверяют
Умеете ли вы разделить три исхода запроса: успех, ответ сервера с ошибкой и отсутствие ответа вообще, и довести каждый до понятного состояния экрана. Следом обычно спрашивают про корутины: как не сломать отмену, где ловить исключения и что делать с истёкшим токеном.
Как отвечать
Опишите слои, а не один колбэк во фрагменте:
- сеть: Retrofit с
suspend-методами поверх OkHttp. Если метод возвращаетResponse<T>, код 4xx или 5xx приходит объектом сisSuccessful == false(успехом считается диапазон 200..299). Если метод возвращаетTнапрямую, Retrofit бросаетHttpException. Обрыв связи и таймаут приходят какIOException; - репозиторий: превращает всё это в свой тип, например
sealed interface ApiResult<out T>с вариантамиSuccess,HttpError(code, body)иNetworkError. Тело ошибки разбирается здесь же, чтобы выше не просачивались классы Retrofit; - ViewModel: переводит результат в
UiState(загрузка, данные, ошибка с кнопкой «повторить») и отдаёт его черезStateFlow, а экран подписывается черезcollectAsStateWithLifecycle()в Compose илиrepeatOnLifecycleво View; - сквозные вещи: 401 обрабатывает
Authenticatorв OkHttp с обновлением токена, логирование и заголовки уходят в интерсепторы, повтор с экспоненциальной задержкой делают только для идемпотентных запросов.
Ошибки полезно разделить по действию пользователя. Нет сети: предложить проверить подключение и повторить. 4xx: объяснить, что не так с запросом. 5xx: извиниться и предложить попробовать позже.
Где спотыкаются
Оборачивают вызов в runCatching или catch (e: Exception). Так глотается CancellationException, и корутина продолжает работу после отмены. Его нужно пробрасывать дальше.
Предлагают Volley и ручные Callback как основной подход. Для Kotlin-проекта на корутинах это звучит как ответ из старой кодовой базы и выдаёт отсутствие свежего опыта.
Считают, что успешный ответ всегда содержит тело. У 204 No Content метод body() возвращает null, и !! превращает штатный ответ в краш.