Do not forget to implement Parcelable on Object fields inside your Parcelable Object

In my previous article, I was too lazy to pass an ArrayList of Parcelables as extras. Now I feel rather indulgent — rather, compelled to refactor my code, as I would have to need the other fields for some foreseeable future business rule(s).

I had an ArrayList called Vespers, which implements Parcelable, like so:

public class Vespers implements Parcelable {
@SerializedName("psalmody")
private ArrayList<Psalm> psalms;
@SerializedName("magnificat_antiphon")
private String magnificatAntiphon;
@SerializedName("oratio")
private String commemoration;

//getters, other fields, Builder class
}

And here is my Psalms Object, like so:

public class Psalm {
@SerializedName("chapter")
private Integer chapter;
@SerializedName("verses_latin")
private ArrayList<String> versesLA;
//getters, Builder class
}

Now the Java object Vespers will not work at all; as you need to make a Parcelable implementation:

Take your keyboard cursor to the word “Parcelable”, then hit Alt + Enter to show this dialog. Then select “Add Parcelable Implementation”
protected Vespers(Parcel in) {
magnificatAntiphon = in.readString();
commemoration = in.readString();
}

@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(magnificatAntiphon);
dest.writeString(commemoration);
}

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

public static final Creator<Vespers> CREATOR = new Creator<Vespers>() {
@Override
public Vespers createFromParcel(Parcel in) {
return new Vespers(in);
}

@Override
public Vespers[] newArray(int size) {
return new Vespers[size];
}
};

That’s trouble, right there. Notice that the psalms are not found anywhere in the Parcelable implementaion.

To show you how bad it gets, let us try passing an ArrayList of Vespers across two Activities:

//some imports...
import static com.monicalabbao.1955.divineoffice.view.VesperaleActivity.VESPERS;
public class HoursActivity extends AppCompatActivity {
//some code...
private ArrayList<Vespers> vespers;

//some more code...
private void showWeeklyVesperale() {
Intent intent = new Intent(HoursActivity.this, VesperaleActivity.class);
intent.putParcelableArrayListExtra(VESPERS, vespers);
startActivity(intent);
}
}

And on the receiving Activity:

//...
public class VesperaleActivity extends AppCompatActivity {
public static final String VESPERS = "vespers";
private ArrayList<Vespers> vespers;
@Override
protected void OnCreate(@Nullable Bundle savedInstanceState) {
//...
vespers = ArrayList<>();
vespers = getIntent().getParcelableArrayListExtra(VESPERS);
}
}

Now Run the app.

So far so good. All my Vespers objects have values in them in HoursActivity

There’s bound to be a problem once you get to your receiving Activity (VesperaleActivity), and here goes:

I lost the Psalms!
A closer look

That much is clear, I have lost the values of my psalms in all of my seven Vespers.

To fix this, the Psalm object must implement Parcelable as well:

public class Psalm implements Parcelable {
@SerializedName("chapter")
private Integer chapter;
@SerializedName("verses_latin")
private ArrayList<String> versesLA;

protected Psalm(Parcel in) {
if (in.readByte() == 0) {
chapter = null;
} else {
chapter = in.readInt();
}
versesLA = in.createStringArrayList();
}

@Override
public void writeToParcel(Parcel dest, int flags) {
if (chapter == null) {
dest.writeByte((byte) 0);
} else {
dest.writeByte((byte) 1);
dest.writeInt(chapter);
}
dest.writeStringList(versesLA);
}

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

public static final Creator<Psalm> CREATOR = new Creator<Psalm>() {
@Override
public Psalm createFromParcel(Parcel in) {
return new Psalm(in);
}

@Override
public Psalm[] newArray(int size) {
return new Psalm[size];
}
};
//getters, setters, Builder class...
}

Then, you can make a constructor of the Psalm that takes no values:

public Psalm() {
}

This is just in case you instantiate Psalm objects traditionally (without the Builder class) like so:

Psalm 119

Then, come back to your Vespers class, tear down your old Parcelable implementation, and generate a new one such that:

protected Vespers(Parcel in) {
psalms = in.createTypedArrayList(Psalm.CREATOR);
magnificatAntiphon = in.readString();
commemoration = in.readString();
}

@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeTypedList(psalms);
dest.writeString(magnificatAntiphon);
dest.writeString(commemoration);
}

Basically, Parcelable has ignored your ArrayList of Psalms because it did not know what to do with it — as it wasn’t a Parcelable. But now that Psalm implements Parcelable, we should be able to account for it as well.

Then, Run your app.

That is much better

Now our VesperaleActivity, it can now have the psalmody of each of the Vespers objects that it got from HoursActivity.

The psalms used to be null before.

Thus, you need to remember. If your parent object has other Object types inside as fields, they need to implement Parcelable as well.

In my next article I’m gonna show it to you how it’s done in Kotlin.

Happy coding!

Monica Aspiras Labbao

Written by

Main hustle is Android development. Secondary hustle is teaching Android development, doing iOs, Unity, and UWP. And I do not eat meat during Fridays.

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade