NullPointerException when invoking Handler.sendEmptyMessageDelayed(int, long)

432 views Asked by At

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?

0

There are 0 answers