Чтение и запись массивов объектов Parcelable

У меня есть следующий класс, который читает и записывает массив объектов из / в посылку:

<code>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];
        }
    };
}
</code>

В приведенном выше коде я получаюClassCastException при чтенииreadParcelableArray:

ERROR/AndroidRuntime(5880): Caused by: java.lang.ClassCastException: [Landroid.os.Parcelable;

Что не так в приведенном выше коде? При записи массива объектов, я должен сначала преобразовать массив вArrayList?

UPDATE:

Можно ли преобразовать массив объектов вArrayList и добавить его в посылку? Например, при написании:

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

При чтении:

<code>    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);
    }
</code>

Но теперь я получаюNullPointerException, Вышеуказанный подход верен? Почему он бросает NPE?

 Chetan09 апр. 2012 г., 12:08
Какой тип mConversationMemberList?
 User772333709 апр. 2012 г., 12:14
Я обновил вопрос, это типа MyClass [].

Ответы на вопрос(4)

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);
  }
 28 сент. 2018 г., 08:32
Можете ли вы показать код, еслиMyClass это какой-тоinterface? Я не уверен, как справитьсяMyClass.CREATOR в этом случае.
 28 сент. 2018 г., 11:25
@isabsent, еслиMyClass является интерфейсом, то его реализации должны все реализоватьParcelable и имеют своиCREATORs.
Решение Вопроса

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);
}
 24 июл. 2013 г., 21:37
Кстати, заявления в рамкахif (parcelableArray != null) {...} можно упростить доresultArray = Arrays.copyOf(parcelableArray, parcelableArray.length, MyClass[].class);
 01 июн. 2015 г., 15:01
@LinardArquint, на самом деле пример кода был не очень хорошим. Вы должны использоватьin.createTypedArray() вместо. Пожалуйста, проверьте обновленный пример.
 18 янв. 2013 г., 08:31
Да, название метода немного сбивает с толку. Когда я сталкивался с этой проблемой, единственным способом ее решения было чтение исходников Android, поэтому я решил написать этот ответ.
 18 янв. 2013 г., 06:45
Спасибо, это помогло! Это должно быть разъяснено в документации, потому что именование методов делает его похожим на массив Parcelable - это то, что должно быть написано, когда это явно больше кода.
 01 июн. 2015 г., 12:11
@Michael: Я думаю, это должно быть & quot; mObjList = new MyClass [size]; in.readTypedArray (mObjList, MyClass.CREATOR); & quot; вместо & quot; mObjList = in.readTypedArray (new MyClass [size], MyClass.CREATOR); & quot; потому что in.readTypedArray имеет возвращаемый тип void, но в остальном ваше сообщение мне очень помогло

Я определил вспомогательный метод в 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;
}

Всякий раз, когда мне нужно прочитать пакетный массив объектов 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);
}
 31 мар. 2015 г., 12:29
@Giorgio Barchiesi, в android studio отображается предупреждение: источник - Parcelable, а назначение - MyClass, но приложение работает, как и ожидалось. Как ?
 03 мар. 2017 г., 12:32
@kaushik, спасибо за ваш комментарий, я отредактировал свой ответ, см. новую версию & quot; toMyObject & quot; функция.
 09 янв. 2015 г., 15:06
Полагаю, я сейчас добавлю этот ответ в закладки. Я уже пару раз возвращался, чтобы скопировать этот магический код: D

Caused by: java.lang.ClassCastException: [Landroid.os.Parcelable;

СогласноAPIМетод readParcelableArray возвращает массив Parcelable (Parcelable []), который нельзя просто привести к массиву MyClass (MyClass []).

But now i get Null Pointer Exception.

Трудно сказать точную причину без подробной трассировки стека исключений.

Предположим, вы сделали так, чтобы 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);
  }
 12 нояб. 2015 г., 19:48
точно я не хочу ClassABC, я хочу MyClass
 17 окт. 2012 г., 05:52
Не должно ли это бытьMyClass.class.getClassLoader() вместоgetClass().getClassLoader()? Потому что я думаю, что загрузчик классов используется для поиска класса Parceleable, который мы пытаемся прочитать.

Ваш ответ на вопрос