Labels

Tuesday, June 21, 2011

How to fix Activity.performStop NullPointer Exception

Just now I get a strange NullPointerException when I want to open my preferences activity in my app.

Logcat says:
E/AndroidRuntime(11226): FATAL EXCEPTION: main
E/AndroidRuntime(11226): java.lang.RuntimeException: Unable to stop activity {com.jjoe64.tests/com.jjoe64.tests.MainActivity}: java.lang.NullPointerException
E/AndroidRuntime(11226):  at android.app.ActivityThread.performStopActivityInner(ActivityThread.java:2430)
E/AndroidRuntime(11226):  at android.app.ActivityThread.handleStopActivity(ActivityThread.java:2475)
E/AndroidRuntime(11226):  at android.app.ActivityThread.access$1800(ActivityThread.java:117)
E/AndroidRuntime(11226):  at android.app.ActivityThread$H.handleMessage(ActivityThread.java:948)
E/AndroidRuntime(11226):  at android.os.Handler.dispatchMessage(Handler.java:99)
E/AndroidRuntime(11226):  at android.os.Looper.loop(Looper.java:130)
E/AndroidRuntime(11226):  at android.app.ActivityThread.main(ActivityThread.java:3683)
E/AndroidRuntime(11226):  at java.lang.reflect.Method.invokeNative(Native Method)
E/AndroidRuntime(11226):  at java.lang.reflect.Method.invoke(Method.java:507)
E/AndroidRuntime(11226):  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:839)
E/AndroidRuntime(11226):  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:597)
E/AndroidRuntime(11226):  at dalvik.system.NativeStart.main(Native Method)
E/AndroidRuntime(11226): Caused by: java.lang.NullPointerException
E/AndroidRuntime(11226):  at android.app.Activity.performStop(Activity.java:3885)
E/AndroidRuntime(11226):  at android.app.ActivityThread.performStopActivityInner(ActivityThread.java:2427)
E/AndroidRuntime(11226):  ... 11 more

There's no method called, which was written by me. So, is it an Android bug?
The best idea now is to take a look in the source code of Android:
final void performStop() {
//[...]    
 synchronized (mManagedCursors) {
  final int N = mManagedCursors.size();
  for (int i=0; i<N; i++) {
   ManagedCursor mc = mManagedCursors.get(i);
   if (!mc.mReleased) {
   mc.mCursor.deactivate(); // -------> NullPointer
   mc.mReleased = true;
  }
 }
//[...]
}

It's clear, that the problem is that a cursor is "null".
So the reason of that issue was found fast: Never return "null" in your content provider's query method.
Instead of null, you should throw an exception or return an empty MatrixCursor like that:
return new MatrixCursor(new String[] {"_id"}); // never return null

A really nice way to detect, null-cursor managing, is to override the startManagingCursor method:
 @Override
 public void startManagingCursor(Cursor c) {
  if (c == null) {
   throw new IllegalStateException("cannot manage cursor: cursor == null");
  }
  super.startManagingCursor(c);
 }

4 comments:

  1. Apsolutelly brilliant... You helped me a lot...
    Thank you...

    Conclusion: NEVER RETURN NULL!!! :)

    ReplyDelete
  2. thank you very much it helped me a lot !!!

    ReplyDelete