Pass array in Intent using parcelable

a 夏天 提交于 2021-02-08 10:16:34

问题


I would like to send an array of objects between activities. I want to use the parcelable interface and send the data in an intent. However I keep getting errors. I have been stuck for 2 days. Here are some details about my problem.

Class A

private ProjetUI[] mProjects;

private final View.OnClickListener mOnClickListener = new View.OnClickListener() {
    @Override
    public void onClick(View view) {
        Context context = view.getContext();
        Intent intent = new Intent(context, ProjetListActivity.class);
        intent.putExtra(ProjetListActivity.ARG_PROJECTS, mProjects);
        context.startActivity(intent);
    }
};

Class B

ProjetUI[] mProjects = getIntent().getParcelableArrayExtra(ARG_PROJECTS);

I get a compilation error "Incompatible types" After casting to (ProjetUI[]), I get a runtime error "Cannot cast Parcelable[] to ProjetUI[]"

Class Projet

public class ProjetUI implements Parcelable {

private String id;
private String idParent;
private String nom;
private String description;
private List<ProjetColonneUI> colonnes;
private List<VueUI> vues;
private boolean archive;
private String version;
private String commentaire;
private boolean published;
private List<DroitAccesUI> droitAcces;
private String idDossier;
private String typeDossier;
private String idModele;
private List<ProjetDatasetUI> projetDatasets;

protected ProjetUI(Parcel in) {
    id = in.readString();
    idParent = in.readString();
    nom = in.readString();
    description = in.readString();
    colonnes = in.createTypedArrayList(ProjetColonneUI.CREATOR);
    vues = in.createTypedArrayList(VueUI.CREATOR);
    archive = in.readInt() == 1;
    version = in.readString();
    commentaire = in.readString();
    published = in.readInt() == 1;
    droitAcces = in.createTypedArrayList(DroitAccesUI.CREATOR);
    idDossier = in.readString();
    typeDossier = in.readString();
    idModele = in.readString();
    projetDatasets = in.createTypedArrayList(ProjetDatasetUI.CREATOR);
}

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

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

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

@Override
public void writeToParcel(Parcel parcel, int flags) {
    parcel.writeString(getId());
    parcel.writeString(getIdParent());
    parcel.writeString(getNom());
    parcel.writeString(getDescription());
    parcel.writeTypedList(getColonnes());
    parcel.writeTypedList(getVues());
    parcel.writeInt(isArchive() ? 1 : 0);
    parcel.writeString(getVersion());
    parcel.writeString(getCommentaire());
    parcel.writeInt(isPublished() ? 1 : 0);
    parcel.writeTypedList(getDroitAcces());
    parcel.writeString(getIdDossier());
    parcel.writeString(getTypeDossier());
    parcel.writeString(getIdModele());
    parcel.writeTypedList(getProjetDatasets());
}
}

EDIT

This is the complete stacktrace

The other classes implement parcelable just like ProjeUI class. Here is an example of another class that has an enum type and an example of an enum that implements parcelable

public class VueRelationUI implements Parcelable {

private String id;
private String idVue;
private String idRelation;
private RelationType typeRelation;

protected VueRelationUI(Parcel in) {
    id = in.readString();
    idVue = in.readString();
    idRelation = in.readString();
    typeRelation = in.readParcelable(RelationType.class.getClassLoader());
}

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

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

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

@Override
public void writeToParcel(Parcel parcel, int flags) {
    parcel.writeString(getId());
    parcel.writeString(getIdVue());
    parcel.writeString(getIdRelation());
    parcel.writeParcelable(getTypeRelation(), flags);
}
}

ENUM

public enum RelationType implements Parcelable {

INNER,
OUTER;

@Override
public void writeToParcel(Parcel parcel, int flags) {
    parcel.writeInt(ordinal());
}

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

public static final Creator<RelationType> CREATOR = new Creator<RelationType>() {
    @Override
    public RelationType createFromParcel(Parcel parcel) {
        return RelationType.values()[parcel.readInt()];
    }

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

Any help would be much appreciated


回答1:


The problem happens because of the internal implementation of Android's Parcel class. When you start the new activity, all of the intent extras are parceled and then unparceled. When this happens, the Android framework allocates a new Parcelable[], and not a new ProjetUI[]. So you get a ClassCastException when you try to cast it.

Probably the best solution would be to change your code to use ArrayList<ProjetUI> instead of ProjetUI[]. Then you can use Intent.putParcelableArrayListExtra() and getParcelableArrayListExtra() without any problems.

If you can't do that for some reason, then you will have to manually cast the array one element at a time:

Parcelable[] parcelables = getIntent().getParcelableArrayExtra(ARG_PROJECTS);
ProjetUI[] mProjects = new ProjetUI[parcelables.length];

for (int i = 0; i < parcelables.length; ++i) {
    mProjects[i] = (ProjetUI) parcelables[i];
}


来源:https://stackoverflow.com/questions/51714927/pass-array-in-intent-using-parcelable

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!