使用 OutOfMemoryException 调用订阅者 onError() 时出现 IllegalStateException
IllegalStateException When Calling Subscriber onError() with OutOfMemoryException
我的代码旨在拍摄原始图像,异步处理它,并让用户看到他们处理过的图像。有时,图像处理会导致 OutOfMemory 错误,然后我想通知用户他们的设备内存不足。
但是,在尝试捕获错误并通知订阅者时,我遇到了崩溃。此外,当我在代码中放置断点时,会捕获 OutOfMemory 错误,并命中 subscriber.onError(e)
行,但从未达到 onPhotoProcessingError(e)
。
这里是订阅发生的地方:
imageDelegate.cropBitmap(rawPhoto, cameraManager.getPictureRotationDegrees(), cameraManager.getCurrentCameraId() == Camera.CameraInfo.CAMERA_FACING_FRONT)
.subscribeOn(Schedulers.computation())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Subscriber<Bitmap>() {
@Override
public void onNext(Bitmap bitmap)
{
onPhotoProcessed(bitmap);
}
@Override
public void onError(Throwable e)
{
onPhotoProcessingError(e);
}
@Override
public void onCompleted()
{
}
});
下面是捕获 OutOfMemory 错误的代码:
public Observable<Bitmap> cropBitmap(Bitmap rawPhoto, int rotation, boolean isFrontFacing)
{
return Observable.create(new Observable.OnSubscribe<Bitmap>()
{
@Override
public void call(Subscriber<? super Bitmap> subscriber)
{
try
{
// rotates the photo so that it's portrait and cuts off the
// bottom of the photo so that we have a square photo
Bitmap rotatedSquarePhoto = PhotoUtils.rotateAndTruncateBottomOfPictureIntoSquare(rawPhoto, rotation);
rawPhoto.recycle();
// we want to mirror the image to match what the user saw when taking a selfie
if (isFrontFacing)
{
rotatedSquarePhoto = PhotoUtils.reflectAboutYAxis(rotatedSquarePhoto);
}
subscriber.onNext(rotatedSquarePhoto);
}
catch (OutOfMemoryError e)
{
subscriber.onError(e);
}
}
});
}
这里是崩溃的堆栈跟踪:
04-06 16:40:55.303 22729-22729/ E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.emersonboyd, PID: 22729
java.lang.IllegalStateException: Fatal Exception thrown on Scheduler.Worker thread.
at rx.internal.schedulers.ScheduledAction.run(ScheduledAction.java:62)
at android.os.Handler.handleCallback(Handler.java:751)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6119)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:886)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:776)
Caused by: java.lang.OutOfMemoryError: Failed to allocate a 921612 byte allocation with 861608 free bytes and 841KB until OOM
at dalvik.system.VMRuntime.newNonMovableArray(Native Method)
at android.graphics.Bitmap.nativeCreate(Native Method)
at android.graphics.Bitmap.createBitmap(Bitmap.java:879)
at android.graphics.Bitmap.createBitmap(Bitmap.java:856)
at android.graphics.Bitmap.createBitmap(Bitmap.java:787)
at com.emersonboyd.util.PhotoUtils.rotateAndTruncateBottomOfPictureIntoSquare(PhotoUtils.java:225)
at com.emersonboyd.delgate.ImageDelegate.call(ImageDelegate.java:124)
at com.emersonboyd.delgate.ImageDelegate.call(ImageDelegate.java:116)
at rx.Observable.unsafeSubscribe(Observable.java:8460)
at rx.internal.operators.OperatorSubscribeOn.call(OperatorSubscribeOn.java:94)
at rx.internal.schedulers.EventLoopsScheduler$EventLoopWorker.call(EventLoopsScheduler.java:169)
at rx.internal.schedulers.ScheduledAction.run(ScheduledAction.java:55)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:428)
at java.util.concurrent.FutureTask.run(FutureTask.java:237)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:272)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1133)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:607)
at java.lang.Thread.run(Thread.java:761)
如果能帮我指明正确的方向,那就太好了。
这是因为 OutOfMemoryError
被 RxJava
视为 致命错误。此类错误不是 "swallowed" 内部的,也不会传递给 onError
回调。
这是 RxJava1 源代码的片段。在每个内部错误处理块的开头调用此方法:
public static void throwIfFatal(Throwable t) {
if (t instanceof OnErrorNotImplementedException) {
throw (OnErrorNotImplementedException) t;
} else if (t instanceof OnErrorFailedException) {
throw (OnErrorFailedException) t;
} else if (t instanceof OnCompletedFailedException) {
throw (OnCompletedFailedException) t;
}
// values here derived from https://github.com/ReactiveX/RxJava/issues/748#issuecomment-32471495
else if (t instanceof VirtualMachineError) {
throw (VirtualMachineError) t;
} else if (t instanceof ThreadDeath) {
throw (ThreadDeath) t;
} else if (t instanceof LinkageError) {
throw (LinkageError) t;
}
}
OutOfMemoryError
是 VirtualMachineError
.
的后代
更多信息:
https://github.com/ReactiveX/RxJava/issues/296
https://github.com/ReactiveX/RxJava/issues/748
您的问题的解决方案:抓住您的 OutOfMemoryError
但将任何适当的 Exception
子类推入流。
p.s。 提示:对于您的情况,请使用 Observable.fromCallable
而不是 Observable.create
我的代码旨在拍摄原始图像,异步处理它,并让用户看到他们处理过的图像。有时,图像处理会导致 OutOfMemory 错误,然后我想通知用户他们的设备内存不足。
但是,在尝试捕获错误并通知订阅者时,我遇到了崩溃。此外,当我在代码中放置断点时,会捕获 OutOfMemory 错误,并命中 subscriber.onError(e)
行,但从未达到 onPhotoProcessingError(e)
。
这里是订阅发生的地方:
imageDelegate.cropBitmap(rawPhoto, cameraManager.getPictureRotationDegrees(), cameraManager.getCurrentCameraId() == Camera.CameraInfo.CAMERA_FACING_FRONT)
.subscribeOn(Schedulers.computation())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Subscriber<Bitmap>() {
@Override
public void onNext(Bitmap bitmap)
{
onPhotoProcessed(bitmap);
}
@Override
public void onError(Throwable e)
{
onPhotoProcessingError(e);
}
@Override
public void onCompleted()
{
}
});
下面是捕获 OutOfMemory 错误的代码:
public Observable<Bitmap> cropBitmap(Bitmap rawPhoto, int rotation, boolean isFrontFacing)
{
return Observable.create(new Observable.OnSubscribe<Bitmap>()
{
@Override
public void call(Subscriber<? super Bitmap> subscriber)
{
try
{
// rotates the photo so that it's portrait and cuts off the
// bottom of the photo so that we have a square photo
Bitmap rotatedSquarePhoto = PhotoUtils.rotateAndTruncateBottomOfPictureIntoSquare(rawPhoto, rotation);
rawPhoto.recycle();
// we want to mirror the image to match what the user saw when taking a selfie
if (isFrontFacing)
{
rotatedSquarePhoto = PhotoUtils.reflectAboutYAxis(rotatedSquarePhoto);
}
subscriber.onNext(rotatedSquarePhoto);
}
catch (OutOfMemoryError e)
{
subscriber.onError(e);
}
}
});
}
这里是崩溃的堆栈跟踪:
04-06 16:40:55.303 22729-22729/ E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.emersonboyd, PID: 22729
java.lang.IllegalStateException: Fatal Exception thrown on Scheduler.Worker thread.
at rx.internal.schedulers.ScheduledAction.run(ScheduledAction.java:62)
at android.os.Handler.handleCallback(Handler.java:751)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6119)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:886)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:776)
Caused by: java.lang.OutOfMemoryError: Failed to allocate a 921612 byte allocation with 861608 free bytes and 841KB until OOM
at dalvik.system.VMRuntime.newNonMovableArray(Native Method)
at android.graphics.Bitmap.nativeCreate(Native Method)
at android.graphics.Bitmap.createBitmap(Bitmap.java:879)
at android.graphics.Bitmap.createBitmap(Bitmap.java:856)
at android.graphics.Bitmap.createBitmap(Bitmap.java:787)
at com.emersonboyd.util.PhotoUtils.rotateAndTruncateBottomOfPictureIntoSquare(PhotoUtils.java:225)
at com.emersonboyd.delgate.ImageDelegate.call(ImageDelegate.java:124)
at com.emersonboyd.delgate.ImageDelegate.call(ImageDelegate.java:116)
at rx.Observable.unsafeSubscribe(Observable.java:8460)
at rx.internal.operators.OperatorSubscribeOn.call(OperatorSubscribeOn.java:94)
at rx.internal.schedulers.EventLoopsScheduler$EventLoopWorker.call(EventLoopsScheduler.java:169)
at rx.internal.schedulers.ScheduledAction.run(ScheduledAction.java:55)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:428)
at java.util.concurrent.FutureTask.run(FutureTask.java:237)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:272)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1133)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:607)
at java.lang.Thread.run(Thread.java:761)
如果能帮我指明正确的方向,那就太好了。
这是因为 OutOfMemoryError
被 RxJava
视为 致命错误。此类错误不是 "swallowed" 内部的,也不会传递给 onError
回调。
这是 RxJava1 源代码的片段。在每个内部错误处理块的开头调用此方法:
public static void throwIfFatal(Throwable t) {
if (t instanceof OnErrorNotImplementedException) {
throw (OnErrorNotImplementedException) t;
} else if (t instanceof OnErrorFailedException) {
throw (OnErrorFailedException) t;
} else if (t instanceof OnCompletedFailedException) {
throw (OnCompletedFailedException) t;
}
// values here derived from https://github.com/ReactiveX/RxJava/issues/748#issuecomment-32471495
else if (t instanceof VirtualMachineError) {
throw (VirtualMachineError) t;
} else if (t instanceof ThreadDeath) {
throw (ThreadDeath) t;
} else if (t instanceof LinkageError) {
throw (LinkageError) t;
}
}
OutOfMemoryError
是 VirtualMachineError
.
更多信息: https://github.com/ReactiveX/RxJava/issues/296 https://github.com/ReactiveX/RxJava/issues/748
您的问题的解决方案:抓住您的 OutOfMemoryError
但将任何适当的 Exception
子类推入流。
p.s。 提示:对于您的情况,请使用 Observable.fromCallable
而不是 Observable.create