Java嵌套可打包,无法初始化数组

时间:2019-02-01 08:45:11

标签: java android android-intent parcelable

好的,我已经阅读了有关堆栈溢出的几乎每个可包裹问题,并尝试了多种解决方案来解决此问题。因此,总的来说,我有一个Android项目,我想通过ArrayList从一个类向另一个发送2个Intent数组。

注意:这不是嵌套可打包线程here的重复,后者不处理数组。它不是this的副本,因为我使所有嵌套类都可拆分。它不是thisthis的副本,因为我没有使用数组列表,而且我也认识到错误是初始化失败。它不是this的副本,因为在这种情况下,我不需要无参数的构造函数(我已经测试过添加一个,并且它不会改变错误)。它也不是this的副本,因为它不是嵌套在包裹中的包裹。

我必须做一些明显的事情,因为nullpointer错误仅在未初始化我的数组时才会发生。但是,在我知道要多长的时间之前,我无法初始化数组长度。

(作为旁注,也许有人可以让我对readTypedList类以及XXX.Creator的确切功能有更深入的了解,因为毫无疑问,这可能是问题的一部分。对于任何将来拥有相同知识的人问题here是指向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];
        }
    };
}

所以现在我问自己如何解决这个问题,并调查了许多其他有前途名字的线程,但是它们并不能解决我的问题。

Here是我会提供帮助的答案,类似地,here他们建议使用createTypedList()而不是readTypedList()

但是,我尝试了第一个答案,也尝试了this,但它们没有用,因为我事先不知道我希望String[]待多久,而最终却领先了错误错误的数组长度。第二个答案无济于事,因为显然我不想创建新的类型列表,而是使用已经拥有的类型列表,因此,通过创建新列表,我最终得到一个空白列表并丢失了数据。 / p>

所有这些问题的根源是我的包裹嵌套在另一个包裹中并通过以下方式调用:

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 :(得分:1)

您可以按照以下代码进行操作:

像这样使用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];
        }
    };
}

答案 1 :(得分:0)

我仍然无法解决原始问题的后半部分(即如何包裹数组),但是我通过稍微重新设计程序就能够成功实现嵌套包裹的实现。

新设计将实现分为4个嵌套类,并具有直接实现。我还删除了数组,因为无法在包裹中正确初始化它们。

编辑:我也偶然发现this website,它会自动为您创建包裹。非常有用,我希望我以前对此有所了解! 还要注意,显然没有必要创建宗地类来宗地StringFloat。您可以改为调用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];
        }
    };
}