2015-11-05 52 views
13

我想这样做:如何处理在地图中的异常()可观察的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...); 

基本上在call()方法,它可以抛出异常。我如何让观察者在onError()中处理它。或者,这不是考虑这个问题的正确方法吗?

+1

请注意,在像RxJava 2这样的运算符中,'map'允许从lambda中引发已检查的异常。这实际上是RxJava 1中的一个设计缺陷,因为抛出的确切错误无法在映射lambda中的'onError'中传播,而不会被包装为'RuntimeException'。 –

回答

15

rx将总是捕获错误,即使这是RuntimeException。 所以你可以在catch块中抛出某种运行时异常。这实际上应该如何工作。

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

当我尝试这样做时,它会要求我用try-catch包围异常 – Sree

+2

您必须抛出RuntimeException。 JVM不会要求你用try catch包围它。这是想法 –

+0

我做了'call()'抛出一个IOException,但它说重写的方法不抛出IOException – Sree

4

随着1.0.15,有fromCallable工厂方法,让你运行一个Callable实例,你可以抛出checked异常以及每个用户:

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

编辑:

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

我想这会适用于这种情况,但是如果我想要将两张地图链接在一起,并依赖于第一张地图的输出结果怎么办?使用'Func1()'我可以得到返回类型和参数。 – Sree

+0

您必须使用flatMap,try-catch并返回just()或error()。 – akarnokd

+0

你能告诉我一个例子吗? – Sree

3

刚刚创建的helper类此样板提取到另一个地方:

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

你可以这样调用:

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

我不知道情况是怎样的时这个问题首先被问及并得到解答,但RxJava目前包含一个辅助方法用于这个确切目的: Exceptions.propagate(Throwable t)

RxJava Javadoc

方便的方法来直接抛出RuntimeException和错误或包裹的任何其它异常类型为一个RuntimeException。

+1

yup,其接受答案的一部分 – Sree

+0

@Sree哇,实际上我没有发现,我被自定义异常类蒙上了一层阴影。现在我看得更近了,我可以看到实际上有另一个答案在这里使用相同的方法。 – Thorbear