2015-11-05 13 views
13

Voglio fare questo:Come faccio a gestire le eccezioni nella cartina() in un 'osservabile in RxJava

Observable.just(bitmap) 
      .map(new Func1<Bitmap, File>() { 
       @Override 
       public File call(Bitmap photoBitmap) { 

        //File creation throws IOException, 
        //I just want it to hit the onError() inside subscribe() 

        File photoFile = new File(App.getAppContext().getCacheDir(), "userprofilepic_temp.jpg"); 
        if(photoFile.isFile()) {//delete the file first if it exists otherwise the new file won't be created 
         photoFile.delete(); 
        } 
        photoFile.createNewFile(); //saves the file in the cache dir 

        FileOutputStream fos = new FileOutputStream(photoFile); 
        photoBitmap.compress(Bitmap.CompressFormat.JPEG, 90, fos);//jpeg format 
        fos.close(); 

        return photoFile; 

       } 
      }) 
      .subscribe(//continue implementation...); 

In sostanza nel metodo call(), può generare eccezioni. Come posso far sì che l'Observer lo gestisca in onError(). O non è questo il modo giusto di pensarci?

+1

Si noti che in RxJava 2 operatori come 'map' consentono il lancio di eccezioni controllate dal lambda. Questo è stato davvero un difetto di progettazione in RxJava 1 perché l'errore esatto generato non poteva essere propagato in "onError" dalla mappa lambda senza essere racchiuso come 'RuntimeException'. –

risposta

15

rx rileva sempre errori, anche se si tratta di RuntimeException. Quindi puoi lanciare qualche tipo di eccezione di runtime nel blocco catch. Questo è il modo in cui dovrebbe funzionare.

Observable.just(bitmap) 
       .map(b -> { 
        try { 
         // do some work which throws IOException 
         throw new IOException("something went wrong"); 
        } catch (IOException e) { 
         throw new RXIOException(e); 
         // Or you can use 
         throw Exceptions.propagate(e); 
         // This helper method will wrap your exception with runtime one 
        } 
       }).subscribe(o -> { 
        // do something here 
       }, exception -> exception.printStackTrace()); 

public static class RXIOException extends RuntimeException { 
     public RXIOException(IOException throwable) { 
      super(throwable); 
     } 
} 
+0

quando provo a farlo, mi chiede di circondare l'eccezione con un try-catch – Sree

+2

Devi lanciare RuntimeException. JVM non ti chiederà di circondarlo con try catch. Questa è l'idea –

+0

Ho fatto 'call()' lancia un IOException ma sta dicendo che il metodo sovrascritto non getta IOException – Sree

4

Con 1.0.15, c'è il metodo fromCallable fabbrica che ti permette di eseguire un'istanza Callable per ogni abbonato, dove si può buttare eccezioni controllate così:

Observable.fromCallable(() -> {  
    File photoFile = new File(App.getAppContext().getCacheDir(), 
     "userprofilepic_temp.jpg"); 
    if (photoFile.isFile()) { 
     //delete the file if it exists otherwise the new file won't be created 
     photoFile.delete(); 
    } 
    photoFile.createNewFile(); //saves the file in the cache dir 

    FileOutputStream fos = new FileOutputStream(photoFile); 
    photoBitmap.compress(Bitmap.CompressFormat.JPEG, 90, fos);//jpeg format 
    fos.close(); 

    return photoFile; 
}) 
.subscribe(...) 

Edit:

source.flatMap(v -> { 
    try { 
     //... 
     return Observable.just(result); 
    } catch (Exception e) { 
     return Observable.error(e); 
    } 
}) 
.subscribe(...); 
+0

Immagino che questo funzionerebbe per questo caso, ma cosa succede se voglio concatenare due mappe che si basano sull'output della prima mappa. Usando 'Func1()' Posso ottenere il tipo di ritorno e argomento. – Sree

+0

Devi usare flatMap, provare a prendere e restituire solo() o error(). – akarnokd

+0

potresti mostrarmi un esempio? – Sree

3

classe helper appena creato per estrarre questo boilerplate in un altro luogo:

public class RxRethrow { 
    public static <T, R> Func1<T, R> rethrow(Func1R<T, R> catchedFunc) { 
     return t -> { 
      try { 
       return catchedFunc.call(t); 
      } catch (Exception e) { 
       throw Exceptions.propagate(e); 
      } 
     }; 
    } 

    public interface Func1R<T, R> extends Function { 
     R call(T t) throws Exception; 
    } 
} 

si può chiamare in questo modo:

.map(RxRethrow.rethrow(products -> mapper.writer(schema).writeValueAsString(products))) 
2

non so come la situazione è stato quando questa domanda è stata prima chiesta e ha risposto, ma RxJava attualmente contiene un metodo di supporto per questo esatto scopo: Exceptions.propagate(Throwable t)

RxJava Javadoc

Metodo pratico per gettare un RuntimeException ed Error direttamente o avvolgere qualsiasi altro tipo di eccezione in un RuntimeException.

+1

yup, parte della risposta accettata – Sree

+0

@Sree Wow, in realtà non l'ho notato, sono stato accecato dalla classe di eccezioni personalizzate. Ora che guardo più da vicino posso vedere che in realtà qui c'è un'altra risposta usando lo stesso metodo. – Thorbear

Problemi correlati