Java вложенный, не может инициализировать массив - PullRequest
0 голосов
/ 01 февраля 2019

Хорошо, я прочитал почти каждый отдельный вопрос о переполнении стека и попробовал несколько решений, чтобы решить эту проблему.Итак, в целом у меня есть проект Android, и я хочу отправить 2 ArrayList с массивов из одного класса в другой через Intent.

Примечание: это не дубликат вложенного потокового потока здесь , который не работает с массивами.Это не дубликат this , потому что я сделал все вложенные классы пригодными для сортировки.Это не дубликат this или this , потому что я не использую список массивов, а также признаю, что ошибка является ошибкой инициализации.Это не дубликат this , потому что в этой ситуации мне не нужен конструктор без параметров (я тестировал добавление одного, и это не меняет ошибку).Это также не дубликат this , потому что это не участок, вложенный в участок.

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

(в качестве примечания, возможно, кто-то мог бы дать мне более глубокое понимание класса readTypedListи что именно XXX.Creator делает, потому что это, несомненно, может быть частью проблемы. Также для любых будущих людей с такой же проблемой здесь является ссылкой на Parcel javadoc, который был информативным, но не решил моюпроблема.)

Так что теперь у меня есть объект 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().

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

Ответы [ 2 ]

0 голосов
/ 03 февраля 2019

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

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

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

Вот мой код:

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

  • Класс посылки A , который содержит 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];
        }
    };
}
0 голосов
/ 01 февраля 2019

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

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