Saw this crash in Crashlytics after recent app release. It happens 100% in background; 50% in Sony, some in Huawei / Xiaomi, not in Samsung; 79% in Android 10, 19% in Android 8.
Fatal Exception: java.lang.NullPointerException: Attempt to invoke virtual method 'boolean android.os.Handler.sendEmptyMessageDelayed(int, long)' on a null object reference at xxx.xxx.xxx.MyEventManager$MyHandler.handleMessage(MyEventManager.java:80) at android.os.Handler.dispatchMessage(Handler.java:107) at android.os.Looper.loop(Looper.java:359) at android.os.HandlerThread.run(HandlerThread.java:67)
Code snippet:
public class MyEventManager { private static class SingletonInstance { private static final MyEventManager INSTANCE = new MyEventManager(); } public static MyEventManager getInstance() { return SingletonInstance.INSTANCE; } private HandlerThread mHandlerThread; private Handler mHandler; private class MyHandler extends Handler { public MyHandler(@NonNull Looper looper) { super(looper); } @Override public void handleMessage(@NonNull Message message) { super.handleMessage(message); switch (message.what) { case ACTION_SEND_REQUEST: if (isThreadReady()) { queryDatabaseAndSendRequest(); mHandler.sendEmptyMessageDelayed(ACTION_SEND_REQUEST, 600 * 1000); } break; default: break; } } } private boolean isThreadReady() { return mHandler != null && mHandlerThread != null && mHandlerThread.getState() != Thread.State.TERMINATED; } private void initHandlerThreadIfNeeded() { if (!isThreadReady()) { mHandlerThread = new HandlerThread(TAG_HANDLER); mHandlerThread.start(); mHandler = new MyHandler(mHandlerThread.getLooper()); } } public void stopAll() { if (mHandler != null) { mHandler.removeCallbacksAndMessages(null); mHandler = null; } if (mHandlerThread != null) { mHandlerThread.quit(); mHandlerThread = null; } } }
The class MyEventManager
periodically sends some data to server; as you can see from the code snippet, it calls mHandler.sendEmptyMessageDelayed()
in handleMessage()
to schedule the next trigger.
The method stopAll()
is called in MainActivity
's onDestroy()
.
Since it happens 100% in background and mHandler
is set to null in stopAll()
, so I believe that MainActivity
has been destroyed at that moment, but that's strange because any pending messages should have been removed by mHandler.removeCallbacksAndMessages(null)
when stopAll()
is called, furthermore, there is null-checking before calling mHandler.sendEmptyMessageDelayed()
.
Can anyone tell me why I'm getting NPE?