web-dev-qa-db-fra.com

Comment gérer les exceptions dans map () dans un observable dans RxJava

Je veux faire ça:

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

Fondamentalement, dans la méthode call(), il peut lever des exceptions. Comment puis-je faire en sorte que l'Observer le gère dans onError(). Ou n'est-ce pas la bonne façon d'y penser?

17
Sree

rx détectera toujours une erreur, même s'il s'agit de RuntimeException. Vous pouvez donc lancer une sorte d'exception d'exécution dans le bloc catch. Voilà comment cela devrait fonctionner.

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

Avec 1.0.15, il existe la méthode d'usine fromCallable qui vous permet d'exécuter une instance Callable pour chaque abonné où vous pouvez également lever des exceptions vérifiées:

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(...)

Éditer:

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

Je viens de créer une classe d'assistance pour extraire ce passe-partout vers un autre endroit:

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

Vous pouvez l'appeler comme ceci:

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

Je ne sais pas comment était la situation lorsque cette question a été posée et répondue pour la première fois, mais RxJava contient actuellement une méthode d'assistance dans ce but précis: Exceptions.propagate(Throwable t)

Javadoc RxJava

Méthode pratique pour lever directement une RuntimeException et une erreur ou envelopper tout autre type d'exception dans une RuntimeException.

3
Thorbear