Java вложенная часть, не может инициализировать массив

Хорошо, я прочитал почти каждый отдельный вопрос о переполнении стека и попробовал несколько решений, чтобы решить эту проблему. Итак, в целом у меня есть проект для 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[], или если кто-то может опубликовать свой рабочий код для вложенной посылки, включая массив, или, наконец, возможно, кто-то может указать более простой способ передачи этих элементов без вложения двух посылок.

Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
2
0
280
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Вы можете сделать это, как показано ниже:

Используйте 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];
        }
    };
}

что такое размер переменной в for( int i = 0; i < size; i++)? К сожалению, сейчас я не знаю, какой размер мне нужен для моего массива...

JFreeman 01.02.2019 22:28

Спасибо за помощь. Но, к сожалению, я также получаю ошибку в этой строке: a = new String[objects.length]; "Попытка получить длину нулевого массива". Это означает, что in.readArray(null) не нашел элемент.

JFreeman 01.02.2019 23:09

@JFreeman Вы можете увидеть изменение в конструкторе, где ваша программа была сломана;

Chetan Joshi 04.02.2019 08:01

Хорошо здорово! Спасибо за это!

JFreeman 05.02.2019 07:36

Я все еще не могу решить вторую половину исходного вопроса (а именно, как создавать массивы участков), но мне удалось добиться успешной реализации вложенных участков, немного изменив мою программу.

Новый дизайн разбивает реализацию на 4 вложенных класса с прямой реализацией. Я также удалил свои массивы, потому что не смог правильно их инициализировать в посылке.

Обновлено: я также наткнулся на этот сайт, который автоматически создает для вас посылки. Очень полезно, и я хотел бы знать об этом раньше! Также обратите внимание, что явно нет необходимости создавать классы участков для участков String и Float. Вместо этого вы можете вызвать Float.class.getClassLoader() и String.class.getClassLoader(), чтобы использовать посылки CREATORS для этих классов.

Вот мой код:

Класс Q содержит ArrayList из:

  • Класс А, который содержит 2 массива строк и чисел с плавающей запятой

Разбив посылку на более мелкие вложенные посылки, я смог постепенно протестировать посылку, пока не пришел к окончательному решению, которое можно было передать через мой 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];
        }
    };
}

Другие вопросы по теме