Хорошо, я прочитал почти каждый отдельный вопрос о переполнении стека и попробовал несколько решений, чтобы решить эту проблему. Итак, в целом у меня есть проект для Android, и я хочу отправить 2 массива ArrayList из одного класса в другой через Intent.
Note: this is not a duplicate of the nested parcelable thread here which does not deal with arrays. It is not a duplicate of this because I have made all nested classes parcelable. It is not a duplicate of this or this because I am not using an array list and also I recognize the error is a failure of initializing. It is not a duplicate of this because I do not need a parameter-less constructor in this situation (I have tested adding one and it doesn't change the error). It is also not a duplicate of this because it is not a parcel nested in a parcel.
Я должен делать что-то очевидное, потому что ошибка нулевого указателя должна возникать только в том случае, если мой массив не был инициализирован. Однако я не могу инициализировать длину массива, пока не узнаю, какой длины я хочу...
(в качестве примечания, возможно, кто-то мог бы дать мне более полное представление о классе readTypedList и о том, что именно делает XXX.Creator, потому что это, несомненно, может быть частью проблемы. Также для любых будущих людей с той же проблемой здесь является ссылкой на Parcel javadoc, который был познавательно, но не решило мою проблему.)
Итак, теперь у меня есть объект Display. Объект Display используется исключительно для хранения String[] и позволяет его разделять. Строка, которая прерывается, была прокомментирована ниже и должна быть очевидна для любого, кто имеет опыт работы с посылками, потому что она явно не была инициализирована:
class Display implements Parcelable {
String[] labels;
public Display(String[] labels) {
this.labels = labels;
}
protected Display(Parcel in) {
in.readStringArray(this.labels); // **** THIS LINE BREAKS
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeStringArray(this.labels);
}
@Override
public int describeContents() {
return 0;
}
public static final Creator<Display> CREATOR = new Creator<Display>() {
@Override
public Display createFromParcel(Parcel in) {
return new Display(in);
}
@Override
public Display[] newArray(int size) {
return new Display[size];
}
};
}
Итак, теперь я спрашиваю себя, что я могу сделать, чтобы решить эту проблему, и исследовал множество других потоков с многообещающими именами, но они не решили мою проблему.
Здесь был ответом, который я бы хотел, хотя он бы помог, точно так же здесь они предложили использовать createTypedList() вместо readTypedList().
Тем не менее, я попробовал первый ответ, а также это, и они не сработали, потому что я заранее не знаю, как долго я хочу, чтобы мой String[] был, что вместо этого приводит к ошибке неверная длина массива. И второй ответ не помогает, потому что, очевидно, я не хочу создавать новый типизированный список, а вместо этого использую типизированный список, который у меня уже есть, поэтому, создавая новый список, я получаю пустой список и теряю свои данные.
Корень всех этих проблем заключается в том, что моя посылка вложена в другую посылку и вызывается через:
in.readTypedList(allChartLabels, Display.CREATOR);
Поскольку он вложен, CREATOR вызывается таким образом, что очень сильно ограничивает мои возможности и приводит к тому, что я не могу решить проблему.
Во время различных тестов я столкнулся с рядом ошибок, но не нашел решений... (текущая ошибка, которую выдает мой код, - ошибка Попытка получить длину нулевого массива).
Я знаю, что у кого-то есть решение этой проблемы, и для получения более подробной информации вот остальная часть моего кода:
public class SummaryEntry implements Parcelable {
private ArrayList<Calculation> allChartValues; // NOTE: this is another nested parcel class which is basically a duplicate of Display but with float[]
private ArrayList<Display> allChartLabels;
public SummaryEntry() {
// initialize
allChartValues = new ArrayList<>();
allChartLabels = new ArrayList<>();
}
protected SummaryEntry(Parcel in) {
this();
// order in which we do this matters:
in.readTypedList(allChartLabels, Display.CREATOR);
in.readTypedList(allChartValues, Calculation.CREATOR);
}
@Override
public void writeToParcel(Parcel out, int i) {
// order in which we do this matters, must be same as reading typed lists
out.writeTypedList(allChartLabels);
out.writeTypedList(allChartValues);
}
/// ... getters and setters excluded because of irrelevance ///
/// PARCELABLE METHODS
@Override
public int describeContents() {
return 0;
}
public static final Creator<SummaryEntry> CREATOR = new Creator<SummaryEntry>() {
@Override
public SummaryEntry createFromParcel(Parcel in) {
return new SummaryEntry(in);
}
@Override
public SummaryEntry[] newArray(int size) {
return new SummaryEntry[size];
}
};
}
Я ценю, что вы нашли время, чтобы прочитать весь этот длинный пост. В идеале я ищу решение проблемы инициализации String[], или если кто-то может опубликовать свой рабочий код для вложенной посылки, включая массив, или, наконец, возможно, кто-то может указать более простой способ передачи этих элементов без вложения двух посылок.




Вы можете сделать это, как показано ниже:
Используйте writeArray и readArray следующим образом:
Попробуйте с обновленным кодом ниже:
package com.myapplication;
import android.os.Parcel;
import android.os.Parcelable;
public class User implements Parcelable {
String name;
int age;
String [] array;
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(this.name);
dest.writeInt(this.age);
dest.writeStringArray(this.array);
}
public User() {
}
protected User(Parcel in) {
this.name = in.readString();
this.age = in.readInt();
this.array = in.createStringArray();
}
public static final Parcelable.Creator<User> CREATOR = new Parcelable.Creator<User>() {
@Override
public User createFromParcel(Parcel source) {
return new User(source);
}
@Override
public User[] newArray(int size) {
return new User[size];
}
};
}
Спасибо за помощь. Но, к сожалению, я также получаю ошибку в этой строке: a = new String[objects.length]; "Попытка получить длину нулевого массива". Это означает, что in.readArray(null) не нашел элемент.
@JFreeman Вы можете увидеть изменение в конструкторе, где ваша программа была сломана;
Хорошо здорово! Спасибо за это!
Я все еще не могу решить вторую половину исходного вопроса (а именно, как создавать массивы участков), но мне удалось добиться успешной реализации вложенных участков, немного изменив мою программу.
Новый дизайн разбивает реализацию на 4 вложенных класса с прямой реализацией. Я также удалил свои массивы, потому что не смог правильно их инициализировать в посылке.
Обновлено: я также наткнулся на этот сайт, который автоматически создает для вас посылки. Очень полезно, и я хотел бы знать об этом раньше!
Также обратите внимание, что явно нет необходимости создавать классы участков для участков String и Float. Вместо этого вы можете вызвать Float.class.getClassLoader() и String.class.getClassLoader(), чтобы использовать посылки CREATORS для этих классов.
Вот мой код:
Класс Q содержит ArrayList из:
Разбив посылку на более мелкие вложенные посылки, я смог постепенно протестировать посылку, пока не пришел к окончательному решению, которое можно было передать через мой Intent с помощью этого кода:
НА ОТПРАВЛЯЮЩЕМ КОНЦЕ:
// create the parcel
Q parcel = new Q();
ArrayList<String> strings = new ArrayList<>();
ArrayList<Float> stats = new ArrayList<>();
// ... populate arraylists ... //
Intent I = new Intent(CURRENTACTIVITY.this, FUTUREACTIVITY.class);
// PUT THE THING
I.putExtra("Data", parcel);
startActivity(I);
НА ПРИЕМНОЙ СТОРОНЕ:
Q parcel = getIntent().getParcelableExtra("Data"); // get data
ПОЛНЫЙ КОД на рабочую посылку: Этот код очень длинный и повторяющийся, но основной принцип настройки участков ясен и прост для повторного использования, если вы хотите создать свой собственный участок.
// top level parcelable class Q
public class Q implements Parcelable {
private ArrayList<A> element;
public Q()
{
this.element = new ArrayList<A>();
}
public void addToA(A a)
{
element.add(a);
}
public ArrayList<A> getA() {
return element;
}
public void setA(ArrayList<A> a) {
this.element = a;
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeTypedList(this.element);
}
private Q (Parcel in){
element = new ArrayList<A>();
in.readTypedList(this.element, A.CREATOR);
}
public static final Parcelable.Creator<Q> CREATOR = new Parcelable.Creator<Q>() {
public Q createFromParcel(Parcel in) {
return new Q(in);
}
public Q[] newArray(int size) {
return new Q[size];
}
};
}
// nested parcel object A
public class A implements Parcelable {
private ArrayList<Float> f;
private ArrayList<String> s;
public A() {
f = new ArrayList<>();
s = new ArrayList<>();
}
public A(ArrayList<Float> f, ArrayList<String> s) {
this.f = f;
this.s = s;
}
public ArrayList<String> getS() {
return s;
}
public void setS(ArrayList<String> s) {
this.s = s;
}
public ArrayList<Float> getF() {
return f;
}
public void setF(ArrayList<Float> f) {
this.f = f;
}
protected A(Parcel in) {
if (in.readByte() == 0x01) {
f = new ArrayList<>();
in.readList(f, Float.class.getClassLoader());
} else {
f = null;
}
if (in.readByte() == 0x01) {
s = new ArrayList<>();
in.readList(s, String.class.getClassLoader());
} else {
s = null;
}
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
if (f == null) {
dest.writeByte((byte) (0x00));
} else {
dest.writeByte((byte) (0x01));
dest.writeList(f);
}
if (s == null) {
dest.writeByte((byte) (0x00));
} else {
dest.writeByte((byte) (0x01));
dest.writeList(s);
}
}
@SuppressWarnings("unused")
public static final Parcelable.Creator<A> CREATOR = new Parcelable.Creator<A>() {
@Override
public A createFromParcel(Parcel in) {
return new A(in);
}
@Override
public A[] newArray(int size) {
return new A[size];
}
};
}
что такое размер переменной в
for( int i = 0; i < size; i++)? К сожалению, сейчас я не знаю, какой размер мне нужен для моего массива...