web-dev-qa-db-fra.com

Lire des tableaux d'écriture d'objets parcellables

J'ai la classe suivante qui lit et écrit un tableau d'objets de/vers une parcelle:

class ClassABC extends Parcelable {
    MyClass[] mObjList;

    private void readFromParcel(Parcel in) {
        mObjList = (MyClass[]) in.readParcelableArray(
                com.myApp.MyClass.class.getClassLoader()));
    }

    public void writeToParcel(Parcel out, int arg1) {
        out.writeParcelableArray(mObjList, 0);
    }

    private ClassABC(Parcel in) {
        readFromParcel(in);
    }

    public int describeContents() {
        return 0;
    }

    public static final Parcelable.Creator<ClassABC> CREATOR =
            new Parcelable.Creator<ClassABC>() {

        public ClassABC createFromParcel(Parcel in) {
            return new ClassABC(in);
        }

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

Dans le code ci-dessus, je reçois un ClassCastException lorsque je lis readParcelableArray:

ERROR/AndroidRuntime (5880): causé par: Java.lang.ClassCastException: [Landroid.os.Parcelable;

Quel est le problème dans le code ci-dessus? Lors de l'écriture du tableau d'objets, devrais-je d'abord convertir le tableau en un fichier ArrayList?

PDATE:

Est-il acceptable de convertir un tableau d'objets en ArrayList et de l'ajouter à une parcelle? Par exemple, en écrivant:

    ArrayList<MyClass> tmpArrya = new ArrayList<MyClass>(mObjList.length);
    for (int loopIndex=0;loopIndex != mObjList.length;loopIndex++) {
        tmpArrya.add(mObjList[loopIndex]);
    }
    out.writeArray(tmpArrya.toArray());

En lisant:

    final ArrayList<MyClass> tmpList = 
            in.readArrayList(com.myApp.MyClass.class.getClassLoader());
    mObjList= new MyClass[tmpList.size()];
    for (int loopIndex=0;loopIndex != tmpList.size();loopIndex++) {
        mObjList[loopIndex] = tmpList.get(loopIndex);
    }

Mais maintenant je reçois un NullPointerException. Est-ce que l'approche ci-dessus est correcte? Pourquoi lance-t-il un NPE?

74
User7723337

Vous devez écrire le tableau à l'aide de la méthode Parcel.writeTypedArray() et le relire avec la méthode Parcel.createTypedArray(), comme suit:

MyClass[] mObjList;

public void writeToParcel(Parcel out) {
    out.writeTypedArray(mObjList, 0);
}

private void readFromParcel(Parcel in) {
    mObjList = in.createTypedArray(MyClass.CREATOR);
}

La raison pour laquelle vous ne devriez pas utiliser les méthodes readParcelableArray()/writeParcelableArray() est que readParcelableArray() crée réellement un Parcelable[] En conséquence. Cela signifie que vous ne pouvez pas convertir le résultat de la méthode en MyClass[]. Au lieu de cela, vous devez créer un tableau MyClass de la même longueur que le résultat et copier chaque élément du tableau de résultats dans le tableau MyClass.

Parcelable[] parcelableArray =
        parcel.readParcelableArray(MyClass.class.getClassLoader());
MyClass[] resultArray = null;
if (parcelableArray != null) {
    resultArray = Arrays.copyOf(parcelableArray, parcelableArray.length, MyClass[].class);
}
151
Michael

ERROR/AndroidRuntime (5880): causé par: Java.lang.ClassCastException: [Landroid.os.Parcelable;

Selon la API , la méthode readParcelableArray renvoie le tableau Parcelable (Parcelable []), qui ne peut pas être simplement converti en tableau MyClass (MyClass []).

Mais maintenant, je suis Null Pointer Exception.

Il est difficile de déterminer la cause exacte sans la trace détaillée de la pile des exceptions.


Supposons que MyClass implémente correctement Parcelable. C’est ce que nous faisons habituellement pour sérialiser/désérialiser un tableau d’objets pouvant être parcellis:

public class ClassABC implements Parcelable {

  private List<MyClass> mObjList; // MyClass should implement Parcelable properly

  // ==================== Parcelable ====================
  public int describeContents() {
    return 0;
  }

  public void writeToParcel(Parcel out, int flags) {
    out.writeList(mObjList);
  }

  private ClassABC(Parcel in) {
    mObjList = new ArrayList<MyClass>();
    in.readList(mObjList, getClass().getClassLoader());
   }

  public static final Parcelable.Creator<ClassABC> CREATOR = new Parcelable.Creator<ClassABC>() {
    public ClassABC createFromParcel(Parcel in) {
      return new ClassABC(in);
    }
    public ClassABC[] newArray(int size) {
      return new ClassABC[size];
    }
  };

}

J'espère que cela t'aides.

Vous pouvez également utiliser les méthodes suivantes:

  public void writeToParcel(Parcel out, int flags) {
      out.writeTypedList(mObjList);
  }

  private ClassABC(Parcel in) {
      mObjList = new ArrayList<ClassABC>();
      in.readTypedList(mObjList, ClassABC.CREATOR);
  }
36
yorkw

J'ai eu un problème similaire, et résolu de cette façon. J'ai défini une méthode d'assistance dans MyClass pour convertir un tableau de Parcelable en un tableau d'objets MyClass:

public static MyClass[] toMyObjects(Parcelable[] parcelables) {
    MyClass[] objects = new MyClass[parcelables.length];
    System.arraycopy(parcelables, 0, objects, 0, parcelables.length);
    return objects;
}

Chaque fois que j'ai besoin de lire un tableau d'objets pouvant être parcellisé, par ex. d'une intention:

MyClass[] objects = MyClass.toMyObjects(getIntent().getParcelableArrayExtra("objects"));

EDIT : Voici une version mise à jour de la même fonction, que j'utilise plus récemment, pour éviter les avertissements de compilation:

public static MyClass[] toMyObjects(Parcelable[] parcelables) {
    if (parcelables == null)
        return null;
    return Arrays.copyOf(parcelables, parcelables.length, MyClass[].class);
}
10
Giorgio Barchiesi

Vous devez écrire le tableau à l'aide de la méthode Parcel.writeTypedArray() et le relire avec la méthode Parcel.readTypedArray(), comme suit:

MyClass[] mObjArray;

public void writeToParcel(Parcel out, int flags) {
    out.writeInt(mObjArray.length);
    out.writeTypedArray(mObjArray, flags);
}

protected MyClass(Parcel in) {
    int size = in.readInt();
    mObjArray = new MyClass[size];
    in.readTypedArray(mObjArray, MyClass.CREATOR);
}

Pour les listes, vous pouvez effectuer les opérations suivantes:

  ArrayList<MyClass> mObjList;

  public void writeToParcel(Parcel out, int flags) {
      out.writeTypedList(mObjList);
  }

  protected MyClass(Parcel in) {
      mObjList = new ArrayList<>(); //non-null reference is required
      in.readTypedList(mObjList, MyClass.CREATOR);
  }
5
EpicPandaForce