Мне нужно перехватить исключение UnknownHostException внутри метода Disposable .subscribe для одного конкретного сетевого вызова, используя RxJava2.
В одном из моих приложений для Android я получил очень случайную ошибку, на воспроизведение которой у меня ушло много времени. Я могу связать это с ненадежным подключением к сети / SIM-карте в Кейптауне, где мы развернули приложение для нескольких сотен пользователей. Ошибка не возникает с эмулятором или с любым телефоном, который я тестировал в Германии.
Все классические тестовые случаи, когда я переключаюсь с Wi-Fi на мобильные данные, выключаю мобильные данные / wifi или перехожу в режим полета, все эти случаи корректно обрабатываются приложением.
Приложение выполняет несколько повторяющихся запросов API и получает данные через FCM. Все они работают нормально. Но есть один запрос на отправку обновления статуса при открытии приложения. Этот запрос не выполняется, если временно возникла проблема с сетью. Я сейчас в Кейптауне для тестирования, и эти проблемы с сетью настолько короткие и частые, что Android не распознает их достаточно быстро для стандартных способов обработки недоступного соединения. Я вижу, что проблема возникает здесь один или два раза в неделю с несколькими сотнями телефонов, работающих 24/7.
Это метод, вызывающий проблемы. Я могу спровоцировать ошибку с закомментированными строками. Это приведет к тому, что на заставке будет отображаться диалог хода выполнения.
public void sendActiveGuardStatus() {
GuardManager guardManager = GuardManager.newInstance(getBaseContext());
showProgress("Loading Operation Status");
Disposable subscription = guardManager
.setGuardAvailable()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.timeout(8, TimeUnit.SECONDS)
.onErrorReturn(e -> {return null;})
.subscribe(
response -> {
// if (Math.random() < 0.5) {
// throw new UnknownHostException("Oh no, no network...");
// }
hideProgress();
startHomeActivity();
}
, throwable -> {
hideProgress();
startLoginActivity();
}
);
addSubscription(subscription);
}
Вот как строится запрос:
public class GuardManager {
public static GuardManager newInstance(Context context) {
return new GuardManager(
context,
RetrofitFactory.build(context).create(GuardNetworkService.class),
new GuardUtils()
);
}
...
public Single<SetGuardStatusResponse> setGuardAvailable() {
return networkService
.setGuardStatus("available")
.compose(response -> TokenErrorTransformer.withErrorCheck(response, context));
}
...
}
public interface GuardNetworkService {
...
@PUT("guardian/set_status_{guard_status}")
Single<SetGuardStatusResponse> setGuardStatus(@Path("guard_status") String status);
...
}
Я хочу поймать исключение, созданное внутри .subscribe (...), и обработать его снаружи вручную. В конце я хочу повторить попытку 3 раза с задержкой между запросами.
Я попробовал onError () и все комбинации try / catch, о которых только мог подумать, но я всегда получаю исключение, подобное этому:
2019-04-01 12:00:37.682 11683-11683/com.lionizers.guardapp W/System.err: io.reactivex.exceptions.UndeliverableException: java.net.UnknownHostException: Oh no, no network...
2019-04-01 12:00:37.682 11683-11683/com.lionizers.guardapp W/System.err: at io.reactivex.plugins.RxJavaPlugins.onError(RxJavaPlugins.java:367)
2019-04-01 12:00:37.682 11683-11683/com.lionizers.guardapp W/System.err: at io.reactivex.internal.observers.ConsumerSingleObserver.onSuccess(ConsumerSingleObserver.java:66)
Я знаю, что мог бы использовать RxJavaPlugins.setErrorHandler, но я не знаю, как я мог бы использовать этот, чтобы специально повторить этот единственный запрос. Все остальные запросы обрабатываются через задачи / потоки, поэтому мне не нужен универсальный обработчик ошибок для любой другой части кода.
- Я что-то упустил концептуально? Есть ли лучший способ продолжить?
- Как бы я поймал исключение, возникшее внутри этого конкретного метода подписки?