Reputation: 1822
Ok mine is definitely different from all other questions asked with this same issue.
Here is my write method:
public Folder(Parcel in, ClassLoader loader) {
id = in.readInt();
persistentId = in.readString();
folderUri = new FolderUri((Uri) in.readParcelable(loader));
name = in.readString();
capabilities = in.readInt();
// 1 for true, 0 for false.
hasChildren = in.readInt() == 1;
syncWindow = in.readInt();
conversationListUri = in.readParcelable(loader);
childFoldersListUri = in.readParcelable(loader);
unseenCount = in.readInt();
unreadCount = in.readInt();
totalCount = in.readInt();
refreshUri = in.readParcelable(loader);
syncStatus = in.readInt();
lastSyncResult = in.readInt();
type = in.readInt();
iconResId = in.readInt();
notificationIconResId = in.readInt();
bgColor = in.readString();
fgColor = in.readString();
if (bgColor != null) {
bgColorInt = Integer.parseInt(bgColor);
}
if (fgColor != null) {
fgColorInt = Integer.parseInt(fgColor);
}
loadMoreUri = in.readParcelable(loader);
hierarchicalDesc = in.readString();
parent = in.readParcelable(loader);
lastMessageTimestamp = in.readLong();
notificationUri = in.readParcelable(loader);
updatedCountUri = in.readParcelable(loader);
unreadSenders = in.readString();
}
Here is my write method:
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(id);
dest.writeString(persistentId);
dest.writeParcelable(folderUri != null ? folderUri.fullUri : null, 0);
dest.writeString(name);
dest.writeInt(capabilities);
// 1 for true, 0 for false.
dest.writeInt(hasChildren ? 1 : 0);
dest.writeInt(syncWindow);
dest.writeParcelable(conversationListUri, 0);
dest.writeParcelable(childFoldersListUri, 0);
dest.writeInt(unseenCount);
dest.writeInt(unreadCount);
dest.writeInt(totalCount);
dest.writeParcelable(refreshUri, 0);
dest.writeInt(syncStatus);
dest.writeInt(lastSyncResult);
dest.writeInt(type);
dest.writeInt(iconResId);
dest.writeInt(notificationIconResId);
dest.writeString(bgColor);
dest.writeString(fgColor);
dest.writeParcelable(loadMoreUri, 0);
dest.writeString(hierarchicalDesc);
dest.writeParcelable(parent, 0);
dest.writeLong(lastMessageTimestamp);
dest.writeParcelable(notificationUri, 0);
dest.writeParcelable(updatedCountUri, 0);
dest.writeString(unreadSenders);
}
This works perfect with no issues. If I DARE change the order of anything in my writeToParcel() method or add a variable and accordingly make the appropriate change in my read from parcel method (i.e. constructor above) I get the above error. I literally can not make a change to it or Android barfs.
Now here is where it gets weird. If I reboot the device then no more crash, no more exception. No code change, just a reboot. This leads me to believe that Android is caching my parcel and completely ignoring what I'm writing to the parcel. I go into debug mode and set a breakpoint in my writeToParcel() method and I can see that it's executing every line but when it goes to read from my parcel it still thinks the order is how it was previously. So if I swap lines for writeInt() with a writeString() and make the change in my constructor, when reading it still thinks the Int was supposed to be where the String was. WTF. Somebody please tell me this is a known bug in Android. Like I said, a reboot fixes this issue.
Here is where I do the parceling. I'm basically creating a PendingIntent that is triggered when a Notification is dismissed.
final Intent cancelNotificationIntent = new Intent(INTENT_ACTION);
cancelNotificationIntent.putExtra(Utils.EXTRA_FOLDER, folder);
notification.setDeleteIntent(PendingIntent.getService(context, notificationId, cancelNotificationIntent, 0));
Here is where I unparcel:
final Folder folder = intent.getParcelableExtra(Utils.EXTRA_FOLDER);
Nothing fancy. Help? If it helps, I'm reproducing this on Android 4.3 and 4.4.
Upvotes: 1
Views: 301
Reputation: 1822
Ok so my issue turned out to be a cached PendingIntent.
final Intent cancelNotificationIntent = new Intent(INTENT_ACTION);
cancelNotificationIntent.putExtra(Utils.EXTRA_FOLDER, folder); // This is the parceled object
notification.setDeleteIntent(PendingIntent.getService(context, notificationId, cancelNotificationIntent, 0));
PendingIntent.getService() when passed a 0 for the flags will continue using the same PendingIntent over and over and completely ignore anything I write to cancelNotificationIntent. I fixed it by changing it to:
notification.setDeleteIntent(PendingIntent.getService(context, notificationId, cancelNotificationIntent, PendingIntent.FLAG_UPDATE_CURRENT));
What I still don't understand is why PendingIntent.getService() continued returning a cached Intent even after the app has been upgraded (i.e. adb install -r app.apk). You would think if the application had been killed or reinstalled that the PendingIntent would be gone but no. Android caches that darned PI indefinitely until you reboot the device.
Hopefully this helps someone else.
Upvotes: 2