Чтение и запись массивов разборных объектов
у меня есть следующий класс, который считывает и записывает массив объектов из/в посылку:
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];
}
};
}
в приведенном выше коде я получаю ClassCastException
при чтении readParcelableArray
:
ошибка / AndroidRuntime (5880): вызвано: java.ленг.ClassCastException: [Landroid.ОС.Parcelable;
что не так в приведенном выше коде? При записи массива объектов, я должен сначала преобразовать массив в ArrayList
?
обновление:
можно ли преобразовать массив объектов в ArrayList
и добавить его в посылку? Например, при написании:
ArrayList<MyClass> tmpArrya = new ArrayList<MyClass>(mObjList.length);
for (int loopIndex=0;loopIndex != mObjList.length;loopIndex++) {
tmpArrya.add(mObjList[loopIndex]);
}
out.writeArray(tmpArrya.toArray());
при чтении:
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);
}
но теперь я получаю NullPointerException
. Выше подход является правильным? Почему он бросает NPE?
4 ответа:
вам нужно написать массив с помощью
Parcel.writeTypedArray()
метод и прочитать его обратно сParcel.createTypedArray()
метод, например, так:MyClass[] mObjList; public void writeToParcel(Parcel out) { out.writeTypedArray(mObjList, 0); } private void readFromParcel(Parcel in) { mObjList = in.createTypedArray(MyClass.CREATOR); }
причина, почему вы не должны использовать
readParcelableArray()
/writeParcelableArray()
методов заключается в том, чтоreadParcelableArray()
действительно создаетParcelable[]
как результат. Это означает, что вы не можете привести результат методMyClass[]
. Вместо этого вы должны создатьMyClass
массив той же длины, что и результат, и скопируйте каждый элемент из массива результатов вMyClass
массив.Parcelable[] parcelableArray = parcel.readParcelableArray(MyClass.class.getClassLoader()); MyClass[] resultArray = null; if (parcelableArray != null) { resultArray = Arrays.copyOf(parcelableArray, parcelableArray.length, MyClass[].class); }
ошибка / AndroidRuntime (5880): вызвано: java.ленг.ClassCastException: [Landroid.ОС.Parcelable;
По словам API, метод readParcelableArray возвращает Parcelable array (Parcelable[]), который не может быть просто приведен к массиву MyClass (MyClass[]).
но теперь я получаю исключение нулевого указателя.
трудно сказать точную причину без детального стека исключений след.
предположим, что вы сделали MyClass реализует Parcelable правильно, это то, как мы обычно делаем для сериализации/десериализации массива parcelable объектов:
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]; } }; }
надеюсь, что это помогает.
вы также можете использовать следующие методы:
public void writeToParcel(Parcel out, int flags) { out.writeTypedList(mObjList); } private ClassABC(Parcel in) { mObjList = new ArrayList<ClassABC>(); in.readTypedList(mObjList, ClassABC.CREATOR); }
у меня была аналогичная проблема, и я решил ее таким образом. Я определил вспомогательный метод в MyClass, для преобразования массива Parcelable в массив объектов MyClass:
public static MyClass[] toMyObjects(Parcelable[] parcelables) { MyClass[] objects = new MyClass[parcelables.length]; System.arraycopy(parcelables, 0, objects, 0, parcelables.length); return objects; }
всякий раз, когда мне нужно прочитать parcelable массив объектов MyClass, например, из намерения:
MyClass[] objects = MyClass.toMyObjects(getIntent().getParcelableArrayExtra("objects"));
EDIT: вот обновленная версия той же функции, которую я использую совсем недавно, чтобы избежать компиляции предупреждений:
public static MyClass[] toMyObjects(Parcelable[] parcelables) { if (parcelables == null) return null; return Arrays.copyOf(parcelables, parcelables.length, MyClass[].class); }
вам нужно написать массив с помощью
Parcel.writeTypedArray()
метод и прочитать его обратно сParcel.readTypedArray()
метод, например, так: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); }
для списков, вы можете сделать следующее:
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); }