2015-01-08 16 views
11

Sto utilizzando la Java più recente RX dove invece dirxJava Android movimentazione con retrofit

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

questo viene utilizzato Errore: (a causa di disapprovazione)

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

(Questo può essere importante come la maggior parte esempio, tutorial, explonation usa quello vecchio ...)

Bene, vediamo il mio problema. Ho una classe Java, parti rilevanti da questa:

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); 
} 

Questo codice funziona quasi perfettamente, se tutto è ok. Ma se faccio un errore intenzionale, come quando spengo il WiFi .. che il retrofit, ottieni il "UnKnownHostException" ... come dovrebbe accadere alla chiamata di aggiornamento (getUser) nel blocco catch try. Ma invece di gestire l'errore su onError (Throwable t) -> dove posso gestire, si blocca semplicemente l'app. Quindi è come se l'errore non arrivasse mai al blocco catch. Ciò che è strano è che errori HTTP (come 404, 401 ecc.) Vengono catturati, ottenuti da onError (...) e tutto va bene.

Tutto va per 3 volte prima del crash, a partire da .retry (3) ma nessuno entra in catch clausola.

EDIT 1

LogCat uscita:

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 

il dato indirizzo api non è quello reale, ma il vero uno è raggiungibile. Ho appena spento il WiFi per testare la gestione degli errori.

E un altro caso d'uso: se aggiungo all'osservabile .onExceptionResumeNext ([2 ° osservabile]) che passa al 2 ° osservabile, e non si blocca. Ma questa non è la soluzione del problema.

EDIT 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()); 
     {...} 
    } 

}); 

EDIT 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) 

Grazie in anticipo per l'aiuto.

+0

Potrebbe pubblicare il tuo traccia dello stack/uscita logcat? Come si presenta il codice chiamante (la definizione dell'osservatore)? –

+0

È stato modificato .. ma in realtà non è troppo rilevante, poiché l'errore è di proposito. ... –

+0

L'output sopra riportato è _non l'app si arresta in modo anomalo_ - è [Retrofit logging the error] (https://github.com/square/retrofit/blob/2c1c6ec370f88e21ac219d8f343f1f6d904c1c87/retrofit/src/main/java/retrofit/RestAdapter.java # L495). Hai un filtro logcat abilitato? ... –

risposta

0

Sembra che si può essere in esecuzione in un problema è stato risolto a partire dal RxJava 1.0:

TrampolineScheduler NullPointerException

+1

Sto usando il modulo Android di rxjava, ora il più recente su jCenter è 0.20.7 dipendenza: compile 'com.netflix.rxjava: rxjava-android: 0.20.7' –

+1

La nuova versione di [RxAndroid] (https: // github.com/ReactiveX/RxAndroid) ha un identificatore differente - compila 'io.reactivex: rxandroid: 0.24.0'. Avrai bisogno di aggiornare i tuoi moduli core RxJava a 1.0 pure. –

+0

Questo sarà il problema che penso. @AdamS Non sono sicuro di cosa intendi "Dovrai aggiornare anche i tuoi moduli core RxJava a 1.0". A proposito, grazie per le vostre risposte. –

3

Non è necessario costruire il proprio osservabile con Retrofit, come retrofit può tornare direttamente osservabile:

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

Retrofit integra anche RxJava per supportare i metodi con un tipo di ritorno di rx.Osservabile

@GET ("/ utente/{id/foto") ObservUserPhoto osservabile (@Path ("id") int id);

(Non sarà necessario per gestire gli errori da soli)

potete inserire lo stacktrace del crash? Come penso tu, che la tua applicazione non dovrebbe bloccarsi.

+1

Grazie, ho appena imparato qualcosa, ho modificato il codice, come consigliato, tagliato tutto il mio Osservabile e modificato: Osservabile getUser (@Field ("username") String userName, @Field ("password") String password); Ma il problema si verifica ancora. Errore non gestito, arresti anomali dell'app. Penso che non sia il problema del Retrofit, ma RX. E ha aggiunto lo stacktrace. –

+0

A proposito, e se mi piacerebbe fare qualcosa con l'oggetto prima che lo gestisca su Observable? -> come qui, al login (username, pass) -> Mi piacerebbe salvare le 'credenziali' nell'oggetto utente, ed è bene scriverlo solo una volta, non tutti i punti di accesso nell'app. Quindi, questo Osservabile può funzionare come una super funzione prima di dire al LoginScreen che qualcosa è successo. –

Problemi correlati