Подтвердить что ты не робот

Android rxJava Обработка ошибок с помощью модификации

Я использую новую RX java, где вместо

Observable.create(new Observable.OnSubscribeFunc<T>() {...});

это используется: (из-за усталости)

Observable.create(new Observable.OnSubscribe<T>() {...});

(Это может быть важно, поскольку большинство примеров, учебник, explonation использует старый...)

Хорошо, давайте посмотрим на мою проблему. У меня есть класс Java, соответствующие его части:

private interface ApiManagerService {

    @FormUrlEncoded
    @POST("/login")
    User getUser(@Field("username") String userName, @Field("password") String password);

}


private static RestAdapter restAdapter = new RestAdapter.Builder()
    .setEndpoint(HOST)
    .setLogLevel(RestAdapter.LogLevel.FULL)
    .build();

private static ApiManagerService apiManager = restAdapter.create(ApiManagerService.class);

public static Subscription login(final String userName, final String password, Observer<User> observer) {
    return Observable.create(new Observable.OnSubscribe<User>() {
        @Override
        public void call(Subscriber<? super User> subscriber) {
            try {

                User user = apiManager.getUser(userName, password);

                subscriber.onNext(user);
                subscriber.onCompleted();

            } catch (RetrofitError e) {
                subscriber.onError(e);
            } catch (Throwable e) {
                subscriber.onError(e);
            }
        }
    }

    ).subscribeOn(Schedulers.io())
     .retry(3)
     .observeOn(AndroidSchedulers.mainThread())
     .subscribe(observer);
}

Этот код почти отлично работает, если все в порядке. Но если я сделаю преднамеренную ошибку, например, я отключу Wi-Fi.., а затем установите "UnKnownHostException" ... как это должно произойти при переоборудовании (getUser) в блоке try catch. Но вместо обработки ошибки toError (Throwable t) → , где я мог бы работать, это просто сбой приложения. Это похоже на то, что ошибка никогда не попадает в блок catch. Странно, что ошибки HTTP (например, 404, 401 и т.д.) Выхватываются, получаются onError (...), и все в порядке.

Все происходит в 3 раза перед сбоем, начиная с .retry(3), но никто не попадает в ловушку.

РЕДАКТИРОВАТЬ 1

Выход LogCat:

    01-08 16:19:31.576  15285-16162/asd.bdef.gh D/Retrofit﹕ ---- ERROR https://testapi.com/api/login
    01-08 16:19:31.606  15285-16162/asd.bdef.gh D/Retrofit﹕ java.net.UnknownHostException: Unable to resolve host "testapi.com": No address associated with hostname
                at java.net.InetAddress.lookupHostByName(InetAddress.java:394)
                at java.net.InetAddress.getAllByNameImpl(InetAddress.java:236)
                at java.net.InetAddress.getAllByName(InetAddress.java:214)
                at com.squareup.okhttp.internal.Network$1.resolveInetAddresses(Network.java:29)
                at com.squareup.okhttp.internal.http.RouteSelector.resetNextInetSocketAddress(RouteSelector.java:259)
                at com.squareup.okhttp.internal.http.RouteSelector.nextProxy(RouteSelector.java:233)
                at com.squareup.okhttp.internal.http.RouteSelector.nextUnconnected(RouteSelector.java:159)
                at com.squareup.okhttp.internal.http.RouteSelector.next(RouteSelector.java:133)
                at com.squareup.okhttp.internal.http.HttpEngine.connect(HttpEngine.java:314)
                at com.squareup.okhttp.internal.http.HttpEngine.sendRequest(HttpEngine.java:237)
                at com.squareup.okhttp.internal.huc.HttpURLConnectionImpl.execute(HttpURLConnectionImpl.java:423)
                at com.squareup.okhttp.internal.huc.HttpURLConnectionImpl.connect(HttpURLConnectionImpl.java:105)
                at com.squareup.okhttp.internal.huc.HttpURLConnectionImpl.getOutputStream(HttpURLConnectionImpl.java:239)
                at com.squareup.okhttp.internal.huc.DelegatingHttpsURLConnection.getOutputStream(DelegatingHttpsURLConnection.java:218)
                at com.squareup.okhttp.internal.huc.HttpsURLConnectionImpl.getOutputStream(HttpsURLConnectionImpl.java:25)
                at retrofit.client.UrlConnectionClient.prepareRequest(UrlConnectionClient.java:68)
                at retrofit.client.UrlConnectionClient.execute(UrlConnectionClient.java:37)
                at retrofit.RestAdapter$RestHandler.invokeRequest(RestAdapter.java:321)
                at retrofit.RestAdapter$RestHandler.access$100(RestAdapter.java:220)
                at retrofit.RestAdapter$RestHandler$1.invoke(RestAdapter.java:265)
                at retrofit.RxSupport$2.run(RxSupport.java:55)
                at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:390)
                at java.util.concurrent.FutureTask.run(FutureTask.java:234)
                at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1080)
                at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:573)
                at retrofit.Platform$Android$2$1.run(Platform.java:142)
                at java.lang.Thread.run(Thread.java:841)
    01-08 16:19:31.606  15285-16162/asd.bdef.gh D/Retrofit﹕ ---- END ERROR
    01-08 16:19:31.977  15285-15285/asd.bdef.gh D/AndroidRuntime﹕ Shutting down VM
    01-08 16:19:31.977  15285-15285/asd.bdef.gh W/dalvikvm﹕ threadid=1: thread exiting with uncaught exception (group=0x41c9d8b0)
    01-08 16:19:31.977  15285-15285/asd.bdef.gh E/AndroidRuntime﹕ FATAL EXCEPTION: main

данный адрес api не является реальным, но реальный доступен. Я просто отключил WiFi, чтобы проверить обработку ошибок.

И еще один прецедент: если я добавлю к наблюдаемому .onExceptionResumeNext([2-й наблюдаемый]), то он станет вторым наблюдаемым, и он не сработает. Но это не решение проблемы.

РЕДАКТИРОВАТЬ 2

ApiManager.login(userName, pass, new Observer<User>() {
    @Override
    public void onCompleted() { }

    @Override
    public void onError(Throwable e) {
        DialogManager.showBasicErrorDialog(getApplicationContext(), e.getLocalizedMessage());
        logger.showLog("Login Not ok");
        e.printStackTrace();
    }

    @Override
    public void onNext(User user) {
        logger.showLog("login ok, user: " + user.getName().toString());
        {...}
    }

}); 

ИЗМЕНИТЬ 3

FATAL EXCEPTION: main
rx.exceptions.OnErrorFailedException: Error occurred when trying to propagate error to Observer.onError
        at rx.observers.SafeSubscriber._onError(SafeSubscriber.java:175)
        at rx.observers.SafeSubscriber.onError(SafeSubscriber.java:97)
        at rx.internal.operators.NotificationLite.accept(NotificationLite.java:144)

{...}

Caused by: java.lang.NullPointerException: Attempt to read from field 'rx.functions.Action0 rx.schedulers.TrampolineScheduler$TimedAction.action' on a null object reference
        at rx.schedulers.TrampolineScheduler$InnerCurrentThreadScheduler.enqueue(TrampolineScheduler.java:85)

Заранее благодарим за помощь.

4b9b3361

Ответ 2

Вам не нужно создавать свои собственные Observable with Retrofit, так как Retrofit может напрямую возвращать Observable:

http://square.github.io/retrofit/

Retrofit также интегрирует RxJava для поддержки методов с возвращаемым типом of rx.Observable

@GET ( "/user/{id}/photo" ) Наблюдаемый getUserPhoto (@Path ( "id" ) int id);

(Вам не придется самостоятельно обрабатывать ошибки)

Можете ли вы опубликовать stacktrace вашего краха? Как я думаю, как вы, ваше приложение не должно терпеть крах.