Search code examples
androidpush-notificationintentserviceandroid-handler

Runnable in Handler not run when posted from inside a push notification IntentService


In my app when I receive a push notification I want to fire a web request to the server to update some data. This is my implementation of IntentService.onHandleIntent(), which is called when I receive a push:

@Override protected void onHandleIntent(Intent intent) {

    final NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
    final NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this);
    // ... notification setup
    notificationManager.notify(Integer.parseInt(intent.getStringExtra("id")), notificationBuilder.build());

    // Web request to the server to update data
    syncData(this);

    // Release the wake lock provided by the WakefulBroadcastReceiver.
    PushNotificationsReceiver.completeWakefulIntent(intent);

}

public static void syncData(final Context content) {
    new Handler().post(new Runnable() {
        @Override public void run() {
            // ... my web request
        }
    });
}

There's no reason in wrapping the request in a Runnable run by an Handler, but the fact is that the runnable is not run. I even checked the return value of post(), and it's true. If I call syncData() from inside an activity, or a fragment, etc, it works as expected, but not in this IntentService. Why is that?

If do this instead, everything works correctly:

public static void syncData(final Context content) {
    // ... my web request
}

Solution

  • In an IntentService, onHandleIntent() will be called on a separate thread created by the IntentService. So when you call new Handler(), a handler instance will be created for that new thread. When you post a runnable using that handler, it will be posted on the new thread's handler and thread's onHandleMessage will be called which is implemented by IntentService and it is ignored.

    If you modify the above code as below it will work

    public static void syncData(final Context content) {
    new Handler(Looper.getMainLooper()).post(new Runnable() {
        @Override public void run() {
            // ... my web request
        }
    });
    }
    

    but in the above Runable will be called on main thread where you should not perform network operation