2017-04-06 43 views
2

我有代碼,旨在採取原始圖像,異步處理,並讓用戶看到他們處理的圖像。有時,圖像處理會導致OutOfMemory錯誤,然後我想通知用戶他們的設備內存不足。IllegalStateException當調用訂閱者onError()與OutOfMemoryException

但是,當我試圖捕捉錯誤並通知訂戶時,我收到崩潰。此外,當我在代碼中放置斷點時,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$2.call(ImageDelegate.java:124) 
     at com.emersonboyd.delgate.ImageDelegate$2.call(ImageDelegate.java:116) 
     at rx.Observable.unsafeSubscribe(Observable.java:8460) 
     at rx.internal.operators.OperatorSubscribeOn$1.call(OperatorSubscribeOn.java:94) 
     at rx.internal.schedulers.EventLoopsScheduler$EventLoopWorker$1.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) 

任何幫助指向正確的方向我會很好。

回答

2

這是因爲OutOfMemoryErrorRxJava視爲致命錯誤。此類錯誤不會在內部「吞噬」,也不會傳遞給onError回調。

這是來自RxJava 源代碼的片段。調用此方法在每個內部錯誤處理區塊的開頭:

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

OutOfMemoryErrorVirtualMachineError後裔。

更多信息: https://github.com/ReactiveX/RxJava/issues/296 https://github.com/ReactiveX/RxJava/issues/748

解決您的問題:抓住你的OutOfMemoryError但推到流的任何適當Exception子類來代替。

p.s. 小費:爲你的情況使用Observable.fromCallable而不是Observable.create

+0

這工作!謝謝 :):) –