Fix For Android Parcelable Extra's Being Null

I came across a useful fix for Android's AlarmReceiver's extras always coming out as null. We need to marshal the Parcelable to a byte array.

The past couple weeks I've been learning some Android development using Android Studio and Java. I'm making a basic RSS notifier which requires some background processing every X minutes (to check the tracked RSS feeds).

I'm using something like the custom AlarmReceiver shown below to handle the application being woken up.

public class FeedUpdaterAlarmReceiver extends WakefulBroadcastReceiver {

    public static final int REQUEST_CODE = 87126;
    public static final String ACTION = "me.isaacjordan.rsstracker.feedupdateralarm";

    // Triggered by the Alarm periodically (starts the service to run task)
    @Override
    public void onReceive(Context context, Intent intent) {
        if (intent.getAction().equals(ACTION)) {
            Log.d("FeedUpdaterAlarmRecv", "Action was correct.");
        } else {
            Log.d("FeedUpdaterAlarmRecv", "Action was not correct!");
            return;
        }

        TrackedFeed trackedFeed = intent.getParcelableExtra("trackedFeed");
        Intent i = new Intent(context, FeedUpdaterService.class);
        i.putExtra("trackedFeed", trackedFeed);
        context.startService(i);
    }
}

This then starts the service that actually checks the feed for new posts. However, I ran in to the issue that my `trackedFeed` was always null. I checked the documentation, checked examples, tried several other forms of passing my TrackedFeed object - however it was still null.

I came across a StackOverflow post that showed a technique that appeared to work. It involves converting the custom Parcelable object to a byte array (byte[]), passing this byte array through the Android Intent, and then converting the byte array back to the Parcelable object. 

The first piece of code required is a utility class to convert a Parcelable class to a byte[]. This is always possible since the point of Parcelable is to indicate the class is serializable in some specific way. All credit for this class goes to Flow on SO.

public class ParcelableUtil {
    public static byte[] marshall(Parcelable parceable) {
        Parcel parcel = Parcel.obtain();
        parceable.writeToParcel(parcel, 0);
        byte[] bytes = parcel.marshall();
        parcel.recycle();
        return bytes;
    }

    public static Parcel unmarshall(byte[] bytes) {
        Parcel parcel = Parcel.obtain();
        parcel.unmarshall(bytes, 0, bytes.length);
        parcel.setDataPosition(0); // This is extremely important!
        return parcel;
    }

    public static <T> T unmarshall(byte[] bytes, Parcelable.Creator<T> creator) {
        Parcel parcel = unmarshall(bytes);
        T result = creator.createFromParcel(parcel);
        parcel.recycle();
        return result;
    }
}

Next we modify our AlarmReceiver to make use of this, as follows.

public class FeedUpdaterAlarmReceiver extends WakefulBroadcastReceiver {

    public static final int REQUEST_CODE = 87126;
    public static final String ACTION = "me.isaacjordan.rsstracker.feedupdateralarm";

    // Triggered by the Alarm periodically (starts the service to run task)
    @Override
    public void onReceive(Context context, Intent intent) {
        if (intent.getAction().equals(ACTION)) {
            Log.d("FeedUpdaterAlarmRecv", "Action was correct.");
        } else {
            Log.d("FeedUpdaterAlarmRecv", "Action was not correct!");
        }

        byte[] bytes = intent.getByteArrayExtra("bytes");

        Intent i = new Intent(context, FeedUpdaterService.class);
        i.putExtra("bytes", bytes);
        context.startService(i);
    }
}

The creation and consumption of the byte[] is as follows:

byte[] bytes = ParcelableUtil.marshall(trackedFeed);
intent.putExtra("bytes", bytes);

// Later
byte[] bytes = intent.getByteArrayExtra("bytes");
TrackedFeed tf = new TrackedFeed(ParcelableUtil.unmarshall(bytes));

Just replace `TrackedFeed` with your own Parcelable class in order to pass objects across an AlarmReceiver in Android! No more null references.

If you enjoyed this post, please check out my other blog posts.