It's happening for 0.08% of our users.
One of the crashes happening on Samsung Galaxy S10 running Android 11
It's not crashing on my Samsung Galaxy S10 running Android 11 though!
Does anyone know why? Line where it crashes
Photo[] photoArray = (Photo[]) bundle.getParcelableArray(EXTRA_PHOTOS);
1st finding
Photo photo1 = new Photo(231, "url", "photoid", "profilid", "caption");
Parcelable[] parcelables1 = new Parcelable[]{photo1};
Photo[] array = (Photo[]) parcelables1;
Throws ClassCastException
This couple with the fact that Bundle#getParcelableArray
only returns a Parcelable array, not the the concrete class Photo array explains why the crash is expected
But why is it only happening for some users only?
2nd finding
This post claims that getParcelableArray()
won't work, only getParcelableArrayListExtra()
or individual casting will work but the why is unclear to me
3rd finding
So I've learnt that downcasting arrays is not supposed to work in Java or Kotlin, at least not in the way Android Bundle do it.
The reason why getParcelableArrayListExtra()
works is because it assume generic type and did work to handle the type.
Question remains: how come getParcelableArray()
works nicely in my real device and emulator? Is there some black magic hidden in plain sight here?
Code below
Photo.java
public class Photo implements Serializable, Model, Parcelable {
private String caption;
private String id, idProfile;
private int position;
private String iphoneFullscreen;
public Photo(int position, String url, String photoId, String profileId, String caption) {
iphoneFullscreen = url;
this.position = position;
this.id = photoId;
idProfile = profileId;
this.caption = caption;
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(this.caption);
dest.writeString(this.id);
dest.writeString(this.idProfile);
dest.writeInt(this.position);
dest.writeString(this.iphoneFullscreen);
}
protected Photo(Parcel in) {
this.caption = in.readString();
this.id = in.readString();
this.idProfile = in.readString();
this.position = in.readInt();
this.iphoneFullscreen = in.readString();
}
public static final Parcelable.Creator<Photo> CREATOR = new Parcelable.Creator<Photo>() {
@Override
public Photo createFromParcel(Parcel source) {
return new Photo(source);
}
@Override
public Photo[] newArray(int size) {
return new Photo[size];
}
};
}
How it's provided and consumed DialogFragmentPhotoGallery.java
public static DialogFragment newInstance(
Photo[] photos) {
DialogFragmentPhotoGallery dialogFragmentPhotoGallery = new DialogFragmentPhotoGallery();
Bundle args = new Bundle();
args.putParcelableArray(DialogFragmentPhotoGallery.EXTRA_PHOTOS, photos);
dialogFragmentPhotoGallery.setArguments(args);
return dialogFragmentPhotoGallery;
}
public View onCreateView(
@NonNull LayoutInflater inflater,
ViewGroup parent,
Bundle savedInstanceState) {
if (getArguments() != null) {
Photo[] photos = (Photo[]) getArguments().getParcelableArray(EXTRA_PHOTOS); // <-- CRASH
// do things with photos
}