Search code examples
androidparcelableparcel

How to create Parcelable code for object that contains GregorianCalendar


I haven't understood how to create the code needed to implement correctly the Parcelable for an object that contains GregorianCalendar objects.

E.g. for an object User that contains String name; and GregorianCalendar creationDate;, my attempt is this:

 @Override
    public int describeContents() {
        return 0;
    }

@Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeString(this.name);
        dest.writeParcelable(this.creationDate, flags);
    }

    private User(Parcel in) {
        this.name = in.readString();
        this.creationDate = in.readParcelable(GregorianCalendar.class.getClassLoader());
    }

    public static final Creator<User> CREATOR = new Creator<User>() {
        public User createFromParcel(Parcel source) {
            return new User(source);
        }

        public User[] newArray(int size) {
            return new User[size];
        }
    };

that unfortunately doesn't work

in writeToParcel() at the line

dest.writeParcelable(this.creationDate, flags);

get writeParcelable cannot be applied to GregorianCalendar error

in

this.creationDate = in.readParcelable(GregorianCalendar.class.getClassLoader());

get Incompatible types error

How to code correctly the Parcelable?

EDIT

I have tried some code generators but use different ways and I'm not sure what is the right implementation, the first one use writeValue and readValue in this way:

 @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeString(name);
        dest.writeValue(creationDate);
    }

 protected User(Parcel in) {
        name = in.readString();
        creationDate = (GregorianCalendar) in.readValue(GregorianCalendar.class.getClassLoader());
    }

the second one use

 @Override
        public void writeToParcel(Parcel dest, int flags) {
            dest.writeString(name);
            dest.writeSerializable(creationDate);
        }

     protected User(Parcel in) {
            name = in.readString();
            creationDate = (GregorianCalendar) in.readSerializable();
        }

What is the right way?


Solution

  • You could use the second way since GregorianCalendar implements Serializable, and the Parcelable will work.

          @Override
          public void writeToParcel(Parcel dest, int flags) {
                dest.writeString(name);
                dest.writeSerializable(creationDate);
          }
    
         protected User(Parcel in) {
                name = in.readString();
                creationDate = (GregorianCalendar) in.readSerializable();
         }
    

    However you MUST NOT serialize GregorianCalendar, because updates in GregorianCalendar related class can cause issue. Consider the case you load a file that contains GregorianCalendar objects created with a different API version, the difference in GregorianCalendar implementation will lead to sure errors, is enough a little difference in serialVersionUID costant to prevent the correct load of the file.

    Use long parameters to store the millisecond of the date, if you don't want to rewrite your whole application you can easily create a couple of methods to convert from millis to GregorianCalendar and vice-versa as you need.