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?