2017-04-06 15 views
2

私は、生のイメージを取得し、非同期に処理し、ユーザーに処理されたイメージを見せるように設計されたコードを持っています。画像処理によってOutOfMemoryエラーが発生することがあります。その場合、そのデバイスにメモリが不足していることをユーザーに通知したい場合があります。IllegalStateException OutOfMemoryExceptionを使用してonError()を呼び出すとき

しかし、エラーをキャッチしてサブスクライバに通知しようとするとクラッシュするようです。さらに、コードにブレークポイントを入れると、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) 

正しい方向で私を指す助けがあれば素晴らしいだろう。 OutOfMemoryErrorRxJava致命的なエラーとして考えられているので、

答えて

2

です。このようなエラーは内部的には「飲み込まれない」ため、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.createの代わりにObservable.fromCallableを使用してください。

+0

これは機能しました。ありがとうございました :):) –

関連する問題