examples icon indicating copy to clipboard operation
examples copied to clipboard

Fixed application crash issue due to NullPointerException on exit

Open hetul-patel opened this issue 4 years ago • 2 comments

There is an issue when application is closed. tlModel is set to null in onDestroy() but InferenceThread still calls tlModel.predict method without checking a null.

Prediction[] predictions = tlModel.predict(rgbImage);

java.lang.NullPointerException is thrown at this line. Solved it using try-catch.

hetul-patel avatar Apr 26 '20 18:04 hetul-patel

@yyoon Thanks for reviewing my PR.

First I would like to answer your second question.

  1. Also, please add a comment explaining why the NullPointerException can be thrown and why we are ignoring it.

As you can see here, in the OnDestroy() method, tlModel is set to a null.

  public void onDestroy() {
    super.onDestroy();
    tlModel.close();
    tlModel = null; // <== tlModel is now a null reference
    Log.d("TFL","onDestroy() completed");
  }

For some reason(I am searching) imageAnalysis use-case is not being unbounded on application exit after onDestroy is completed. As shown below, eventually a call to tfmodel.predict method is made inside inferenceAnalyzer even after tfModel is set to a null and throws a NullPointerExecption.

private final ImageAnalysis.Analyzer inferenceAnalyzer =
          (imageProxy, rotationDegrees) -> {
              ...

              Log.d("TFL","Incoming req for predict");
              Prediction[] predictions = tlModel.predict(rgbImage);

              ...
}

The exact exception thrown is this,

java.lang.NullPointerException: Attempt to invoke virtual method 'org.tensorflow.lite.examples.transfer.api.TransferLearningModel$Prediction[] org.tensorflow.lite.examples.transfer.TransferLearningModelWrapper.predict(float[])' on a null object reference
        at org.tensorflow.lite.examples.transfer.CameraFragment.lambda$new$2$CameraFragment(CameraFragment.java:180)
        at org.tensorflow.lite.examples.transfer.-$$Lambda$CameraFragment$o2DkVL-ukwqtN87dNJz2_ON_zV8.analyze(Unknown Source:2)
        at androidx.camera.core.ImageAnalysisNonBlockingCallback$1.run(ImageAnalysisNonBlockingCallback.java:150)
        at android.os.Handler.handleCallback(Handler.java:873)
        at android.os.Handler.dispatchMessage(Handler.java:99)
        at android.os.Looper.loop(Looper.java:193)
        at android.os.HandlerThread.run(HandlerThread.java:65)

I have logged the sequence of method calls as show below. You can see that last request for prediction is after completion of onDestroy() which is the reason for NullPointerException.

2020-04-27 19:45:57.904 5247-5284/org.tensorflow.lite.examples.transfer D/TFL: Incoming req for predict
2020-04-27 19:45:58.219 5247-5284/org.tensorflow.lite.examples.transfer D/TFL: Incoming req for predict
2020-04-27 19:45:58.534 5247-5284/org.tensorflow.lite.examples.transfer D/TFL: Incoming req for predict
2020-04-27 19:45:58.855 5247-5284/org.tensorflow.lite.examples.transfer D/TFL: Incoming req for predict
2020-04-27 19:45:59.146 5247-5247/org.tensorflow.lite.examples.transfer D/TFL: onDestroy() completed
2020-04-27 19:45:59.227 5247-5284/org.tensorflow.lite.examples.transfer D/TFL: Incoming req for predict

Now coming to the first question.

Could you specifically catch NullPointerException instead? It would be bad to catch all exceptions and ignore them in case something else happens.

Yes sure. I can handle NullPointerException specifically and it solves the app crash. But the primary reason for imageAnalysis use-case not getting unbound is still unknown.

hetul-patel avatar Apr 27 '20 14:04 hetul-patel

Catching a NullPointerException is probably not what we want, we should either add a proper lock for inference or do the closing on the worker thread rather than the UI thread.

jdduke avatar Apr 27 '20 15:04 jdduke