4

It's happening for 0.08% of our users. One of the crashes happening on Samsung Galaxy S10 running Android 11 enter image description here

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
    }
ericn
  • 12,476
  • 16
  • 84
  • 127
  • 1
    (If you're going to mask out the package name in the screenshot, mask them all out! Second line. But then again, you've got the company name in your profile, so...) – Andy Turner Nov 02 '21 at 21:33

0 Answers0