如何创建一个包含嵌套对象的可传递类(Parcelable)

41

我想让A类实现Parcelable。

public class A {
    public String str;
    public ArrayList<B> list;
}

这是我到目前为止想出的。然而,它会因为空指针异常而崩溃。问题在于这两个语句:dest.writeList(list);in.readList(list, this.getClass().getClassLoader());。 我无法从这里找出解决办法 :(

A类

public class A implements Parcelable {
    public String str;
    public ArrayList<B> list;

    @Override
    public int describeContents() {
        // TODO Auto-generated method stub
        return 0;
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeString(str);
        dest.writeList(list);
    }

    private A(Parcel in) {
        str = in.readString();
        in.readList(list, this.getClass().getClassLoader());
    }

    public static final Parcelable.Creator<A> CREATOR
            = new Parcelable.Creator<A>() {
        public A createFromParcel(Parcel in) {
            return new A(in);
        }

        public A[] newArray(int size) {
            return new A[size];
        }
    };
}

B级班

public class B implements Parcelable {
    public String str;

    @Override
    public int describeContents() {
        // TODO Auto-generated method stub
        return 0;
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeString(str);
    }

    private B(Parcel in) {
        str = in.readString();
    }

    public static final Parcelable.Creator<B> CREATOR
            = new Parcelable.Creator<B>() {
        public B createFromParcel(Parcel in) {
            return new B(in);
        }

        public B[] newArray(int size) {
            return new B[size];
        }
    };
}

感谢您花费时间。

7个回答

56

我终于想到在Google中搜索的关键词:),并找到了这个Android中如何正确使用在Parcelable类中的readTypedList方法?

解决方案是改用read-/writeTypedList。为避免任何进一步的NullPointerException,我还初始化了ArrayList。

类A

public class A implements Parcelable {
    public String str;
    public ArrayList<B> list = new ArrayList<B>();

    @Override
    public int describeContents() {
        // TODO Auto-generated method stub
        return 0;
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeString(str);
        dest.writeTypedList(list);
    }

    private A(Parcel in) {
        str = in.readString();
        in.readTypedList(list, B.CREATOR);
    }

    public static final Parcelable.Creator<A> CREATOR
            = new Parcelable.Creator<A>() {
        public A createFromParcel(Parcel in) {
            return new A(in);
        }

        public A[] newArray(int size) {
            return new A[size];
        }
    };
}

B 类

public class B implements Parcelable {
    public String str;

    @Override
    public int describeContents() {
        // TODO Auto-generated method stub
        return 0;
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeString(str);
    }

    private B(Parcel in) {
        str = in.readString();
    }

    public static final Parcelable.Creator<B> CREATOR
            = new Parcelable.Creator<B>() {
        public B createFromParcel(Parcel in) {
            return new B(in);
        }

        public B[] newArray(int size) {
            return new B[size];
        }
    };
}

啊,是的,它不让我这样做,然后我有点忘了它 :) - Snæbjørn
@Snæbjørn +1展示了如何创建一个包含非基本类型或自定义类型的Parcelable类。 - ripopenid
很棒的例子。我可以建议您在两个类中修复“AcreateFromParcel”函数的名称吗?在A类中应该是“public A createFromParcel”(缺少空格),而在B类中应该是“public B createFromParcel”。是的,这很琐碎,但对于新手来说可能会有麻烦。 - Miguel El Merendero

32

如果您的主Parcelable对象中只有一个Parcelable对象,而不是像已被接受的答案那样是列表。那么它将如下所示:

A类

public class A implements Parcelable {
    public String str;
    public B objectB;

    @Override
    public int describeContents() {
        // TODO Auto-generated method stub
        return 0;
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        //The parcelable object has to be the first one
        dest.writeParcelable(objectB, flags);
        dest.writeString(str);
    }

    private A(Parcel in) {
        this.objectB = in.readParcelable(B.class.getClassLoader());
        str = in.readString();
    }

    public static final Parcelable.Creator<A> CREATOR
            = new Parcelable.Creator<A>() {
        public A createFromParcel(Parcel in) {
            return new A(in);
        }

        public A[] newArray(int size) {
            return new A[size];
        }
    };
}

B 类

public class B implements Parcelable {
    public String str;

    @Override
    public int describeContents() {
        // TODO Auto-generated method stub
        return 0;
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeString(str);
    }

    private B(Parcel in) {
        str = in.readString();
    }

    public static final Parcelable.Creator<B> CREATOR
            = new Parcelable.Creator<B>() {
        public B createFromParcel(Parcel in) {
            return new B(in);
        }

        public B[] newArray(int size) {
            return new B[size];
        }
    };
}

重要提示:请注意您编写和读取Parcelable对象的顺序。查看此答案以获取更多详细信息。


3
在“写入包裹”操作中
@Override
public void writeToParcel(Parcel parcel, int i) {
    parcel.writeString(name); //if String
    parcel.writeTypedList(assignedEmployees); //if List with custom class, eg. List<AssignedEmployee> assignedEmployees
    parcel.writeParcelable(checkin,i); //if custom class, eg. Checkin checkin;
    }

在读取器的构造函数中实现它的回读功能。
 protected A(Parcel in) {
        name = in.readString();
        assignedEmployees = in.createTypedArrayList(AssignedEmployee.CREATOR);
        checkin = in.readParcelable(Checkin.class.getClassLoader());
    }

应该在自定义类中实现Parcelable接口,其中包括AssignedEmployee和Checkin。


2
只需按下 ALT+ENTER,然后替换 Parcelable,它将实现所有必要的实现。

尝试这个答案,它会自动完成所有工作,您不需要编写任何代码。 - Alok Singh

1

我也遇到了同样的问题,这里有一个通用版本

class Item<T : Parcelable> (val model: T, val index: Int ) : Parcelable {

    constructor(parcel: Parcel) :
        this(parcel.readParcelable(
          Item<T>::model.javaClass.classLoader),
          parcel.readInt()
        ) {}

    override fun writeToParcel(parcel: Parcel?, flag: Int) {
        parcel?.writeParcelable(model, 0)
        parcel?.writeInt(index)
    }

    override fun describeContents(): Int {
        return 0
    }

    companion object CREATOR : Parcelable.Creator<Item<Parcelable>> {
        override fun createFromParcel(parcel: Parcel): Item<Parcelable> {
            return Item(parcel)
        }

        override fun newArray(size: Int): Array<Item<Parcelable>?> {
            return arrayOfNulls(size)
        }
    }
}

0

您可以从首选项中添加Parcelable代码生成器插件,然后通过以下方式创建Parcelable样板代码: - 在模型内右键单击类名 - 选择生成 - 选择Parcelable

完成 - 您的模型将更新为必要的Parcelable样板代码。


0

很不幸,我正在使用第三方库中的一个类(BarEntry),它无法被打包。 我通过传递 Intent 中的 float 数组并在接收端重新构造我的 BarEntry 对象来解决了这个问题。

这种方法并不是最优解,但如果有人遇到了类似无法创建可打包对象的情况,那么这种方法可能会有用。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接