在Observable.from()中抛出时未捕获RuntimeException

时间:2016-04-16 13:35:14

标签: java android rx-java rx-android

为了在下载文件时更新进度,我自定义了一个InputStreamToFileIterable类来使用rxjava:

public class InputStreamToFileIterable implements Iterable<Integer> {
    private InputStream inputStream;
    private FileOutputStream outputStream;
    private byte[] buffer;


    public InputStreamToFileIterable(InputStream inputStream, FileOutputStream outputStream) {
        this.inputStream = inputStream;
        this.outputStream = outputStream;
        this.buffer = new byte[512];
    }

    public Iterator<Integer> iterator() {
        return new InputStreamIterator();
    }

    class InputStreamIterator implements Iterator<Integer> {
        int data;
        boolean isClosed;
        int read;

        public InputStreamIterator() {
            read = 0;
            try {
                data = inputStream.read(buffer);
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
            isClosed = false;
        }

        @Override
        public boolean hasNext() {
            return data != -1;
        }

        @Override
        public Integer next() {
            read += data;
            try {
                if (isClosed){
                    throw new NoSuchElementException();
                }
                if (!hasNext()) {
                    inputStream.close();
                    outputStream.close();
                    isClosed = true;
                } else {
                    outputStream.write(buffer, 0, data);
                    data = inputStream.read(buffer);
                }
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
            return read;
        }

        @Override
        public void remove() {
            throw new UnsupportedOperationException();
        }

    }
}

然而,当我订阅像这样的Observable时:

subscriptionList.add(Observable.just(cachePath)
            .concatMap(new Func1<String, Observable<Integer>>() {
                @Override
                public Observable<Integer> call(String s) {
                    try {
                        isDownloading = true;
                        HttpURLConnection connection = (HttpURLConnection) new URL(url).openConnection();
                        connection.connect();
                        if (!file.getParentFile().exists()) {
                            file.getParentFile().mkdirs();
                        }
                        file.createNewFile();
                        fileOutputStream = new FileOutputStream(cachePath);
                        inputStream = connection.getInputStream();
                        total = connection.getContentLength();
                        return Observable.from(new InputStreamToFileIterable(inputStream, fileOutputStream));
                    } catch (Exception e) {
                        Log.d(TAG, e.getMessage());
                    }
                    return Observable.just(null);
                }
            })
            .filter(new Func1<Integer, Boolean>() {
                @Override
                public Boolean call(Integer integer) {
                    return integer!=null;
                }
            })
            .subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(getObserverDownloadPicture()));

如果inputStream中途关闭,我的观察者无法捕获InputStreamIterator.next()抛出的RuntimeException。我将得到如下异常:

04-16 22:39:18.393 16996-17031/me.wuke.weibo E/AndroidRuntime: FATAL EXCEPTION: RxCachedThreadScheduler-2
                                                           Process: me.wuke.weibo, PID: 16996
                                                           Theme: themes:{default=overlay:system, iconPack:system, com.android.systemui=overlay:system, com.android.systemui.navbar=overlay:system}
                                                           java.lang.IllegalStateException: Fatal Exception thrown on Scheduler.Worker thread.
                                                               at rx.internal.schedulers.ScheduledAction.run(ScheduledAction.java:62)
                                                               at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:423)
                                                               at java.util.concurrent.FutureTask.run(FutureTask.java:237)
                                                               at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:269)
                                                               at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1113)
                                                               at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:588)
                                                               at java.lang.Thread.run(Thread.java:818)
                                                            Caused by: java.lang.RuntimeException: java.net.SocketException: recvfrom failed: ETIMEDOUT (Connection timed out)
                                                               at me.wuke.weibo.utility.InputStreamToFileIterable$InputStreamIterator.next(InputStreamToFileIterable.java:60)
                                                               at me.wuke.weibo.utility.InputStreamToFileIterable$InputStreamIterator.next(InputStreamToFileIterable.java:27)
                                                               at rx.internal.operators.OnSubscribeFromIterable$IterableProducer.slowpath(OnSubscribeFromIterable.java:97)
                                                               at rx.internal.operators.OnSubscribeFromIterable$IterableProducer.request(OnSubscribeFromIterable.java:73)
                                                               at rx.internal.producers.ProducerArbiter.request(ProducerArbiter.java:66)
                                                               at rx.internal.operators.OperatorConcat$ConcatSubscriber.requestFromChild(OperatorConcat.java:124)
                                                               at rx.internal.operators.OperatorConcat$ConcatSubscriber.access$000(OperatorConcat.java:75)
                                                               at rx.internal.operators.OperatorConcat$ConcatProducer.request(OperatorConcat.java:70)
                                                               at rx.internal.operators.OperatorSubscribeOn$1$1$1$1.call(OperatorSubscribeOn.java:85)
                                                               at rx.internal.schedulers.ScheduledAction.run(ScheduledAction.java:55)
                                                               at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:423) 
                                                               at java.util.concurrent.FutureTask.run(FutureTask.java:237) 
                                                               at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:269) 
                                                               at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1113) 
                                                               at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:588) 
                                                               at java.lang.Thread.run(Thread.java:818) 
                                                            Caused by: java.net.SocketException: recvfrom failed: ETIMEDOUT (Connection timed out)
                                                               at libcore.io.IoBridge.maybeThrowAfterRecvfrom(IoBridge.java:588)
                                                               at libcore.io.IoBridge.recvfrom(IoBridge.java:552)
                                                               at java.net.PlainSocketImpl.read(PlainSocketImpl.java:481)
                                                               at java.net.PlainSocketImpl.-wrap0(PlainSocketImpl.java)
                                                               at java.net.PlainSocketImpl$PlainSocketInputStream.read(PlainSocketImpl.java:237)
                                                               at com.android.okhttp.okio.Okio$2.read(Okio.java:135)
                                                               at com.android.okhttp.okio.AsyncTimeout$2.read(AsyncTimeout.java:211)
                                                               at com.android.okhttp.okio.RealBufferedSource.read(RealBufferedSource.java:50)
                                                               at com.android.okhttp.internal.http.HttpConnection$FixedLengthSource.read(HttpConnection.java:418)
                                                               at com.android.okhttp.okio.RealBufferedSource.read(RealBufferedSource.java:50)
                                                               at com.android.okhttp.internal.http.HttpEngine$2.read(HttpEngine.java:942)
                                                               at com.android.okhttp.okio.RealBufferedSource$1.read(RealBufferedSource.java:349)
                                                               at java.io.InputStream.read(InputStream.java:162)
                                                               at me.wuke.weibo.utility.InputStreamToFileIterable$InputStreamIterator.next(InputStreamToFileIterable.java:57)
                                                               at me.wuke.weibo.utility.InputStreamToFileIterable$InputStreamIterator.next(InputStreamToFileIterable.java:27) 
                                                               at rx.internal.operators.OnSubscribeFromIterable$IterableProducer.slowpath(OnSubscribeFromIterable.java:97) 
                                                               at rx.internal.operators.OnSubscribeFromIterable$IterableProducer.request(OnSubscribeFromIterable.java:73) 
                                                               at rx.internal.producers.ProducerArbiter.request(ProducerArbiter.java:66) 
                                                               at rx.internal.operators.OperatorConcat$ConcatSubscriber.requestFromChild(OperatorConcat.java:124) 
                                                               at rx.internal.operators.OperatorConcat$ConcatSubscriber.access$000(OperatorConcat.java:75) 
                                                               at rx.internal.operators.OperatorConcat$ConcatProducer.request(OperatorConcat.java:70) 
                                                               at rx.internal.operators.OperatorSubscribeOn$1$1$1$1.call(OperatorSubscribeOn.java:85) 
                                                               at rx.internal.schedulers.ScheduledAction.run(ScheduledAction.java:55) 
                                                               at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:423) 
                                                               at java.util.concurrent.FutureTask.run(FutureTask.java:237) 
                                                               at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:269) 
                                                               at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1113) 
                                                               at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:588) 
                                                               at java.lang.Thread.run(Thread.java:818) 
                                                            Caused by: android.system.ErrnoException: recvfrom failed: ETIMEDOUT (Connection timed out)
                                                               at libcore.io.Posix.recvfromBytes(Native Method)
                                                               at libcore.io.Posix.recvfrom(Posix.java:189)
                                                               at libcore.io.BlockGuardOs.recvfrom(BlockGuardOs.java:250)
                                                               at libcore.io.IoBridge.recvfrom(IoBridge.java:549)

我没有忘记在我的观察者中实现onError()方法。

    public Observer getObserverDownloadPicture() {
    return Observers.create(
            new Action1<Integer>() {
                @Override
                public void call(Integer integer) {
                    onProgressChanged(integer * 100 / total);
                }
            }
            , new Action1<Throwable>() {
                @Override
                public void call(Throwable throwable) {
                    Log.e(TAG, throwable.getMessage());
                    try {
                        fileOutputStream.close();
                        isDownloading = false;
                        file.delete();
                    } catch (Exception e) {
                        ExceptionUtils.saveLog(e);
                    }
                    progressTextView.setText("载入失败");
                    subscriptionList.clear();
                }
            }
            , new Action0() {
                @Override
                public void call() {
                    try {
                        fileOutputStream.close();
                    } catch (Exception e) {
                        Log.d(TAG, e.getMessage());
                    }
                    if (isDownloading) {
                        setupPicture();
                    }
                    isDownloading = false;
                    subscriptionList.clear();
                }
            }
    );
}

如何处理异常?请帮助我。

1 个答案:

答案 0 :(得分:0)

尝试使用具体异常替换catch块中的Exception。像这样:

catch (IOException e) {
    Log.d(TAG, e.getMessage());
}
相关问题