Parcelable继承:抽象类 - 使用哪个CREATOR?

8

我有一个抽象类 A,它实现了 Parcelable 接口。

我有两个类 BC,它们都继承自 A。如何使它们可被序列化?

当然,我可以像许多帖子中建议的那样,在 AB 中都提供一个 CREATOR,并将它们链接起来。但是,由于我有其他存储 A-B-C 类的对象,并且它们本身实现了 Parcelable 接口,所以这种方法似乎行不通,因为当我想传递一个 A 的 ArrayList 时,我必须在类型化列表中使用 CREATOR

ArrayList<A> elements = new ArrayList<>();
in.readTypedList(elements , B.CREATOR); // B.CREATOR? C.CREATOR???

显然这没有任何意义。那么我该如何正确地使A成为可 Parcelable 的呢?
即我想要将这个类变成 Parcelable,以便可以以通用的方式引用 A。
A)
public abstract class A implements Parcelable {

    final String globalVar;

    public A(String globalVar) {
        this.globalVar = globalVar;
    }
}

B)

public class B extends A {

    String bVar;


    public B(String global, String bVar) {
        super(global);
        this.bVar = bVar;
    }

    private B(Parcel in) {
        super(in.readString());
        this.bVar = in.readString();
    }


    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel parcel, int i) {
        parcel.writeString(bVar);
    }
}

C)

public class C extends A {

    String cVar;


    public C(String global, String cVar) {
        super(global);
        this.cVar = cVar;
    }

    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel parcel, int i) {
        parcel.writeString(cVar);
    }
}

哪一个是抽象的? - Blackbelt
但是在A中你不能有一个创建者,因为它无法实例化。如果你至少发布A的一部分,那么就会更容易些。 - Blackbelt
正如我所说,如果您至少发布A,那将更容易。 - Blackbelt
你能否尝试让A实现Parcelable接口,看看会发生什么? - Blackbelt
这是不正确的。为了能够写入A的对象(例如globalVar),您还应该在A中实现writeToParcel。您还应该在A中实现以Parcel为参数的构造函数。B和C必须调用 super.writeToParcel(...)super(in) - Blackbelt
显示剩余4条评论
2个回答

12
我使用了 Vincent Mimoun-Prat 在以下文章中介绍的可序列化架构:Parcelable and inheritance in Android,并遇到了同样的类型列表问题,需要指定一个不可能的抽象 CREATOR。
在 Parcel 的 JavaDoc 中搜索,我找到了方法 writeList(List val),它内部使用 writeValue(Object) 方法来处理列表中的每个对象,并因此调用子类(从 A 列表中的 B 和 C)的 writeToParcel() 方法。要反序列化列表,请使用其对应的 readList (List outVal, ClassLoader loader) 方法,其中必须传递 A ClassLoader,否则会抛出 android.os.BadParcelableException 异常(至少在我的情况下如此)。
包含 A 元素列表的类应该像这样:
public class AContainer implements Parcelable {
    //Other AContainer fields
    List<A> elements = new ArrayList<>();
    //Other AContainer fields

    static final Parcelable.Creator<AContainer> CREATOR = new Parcelable.Creator<AContainer>() {
        @Override
        public AContainer createFromParcel(Parcel source) {
            return new AContainer(source);
        }

        @Override
        public AContainer[] newArray(int size) {
            return new AContainer[size];
        }
    };

    public AContainer() {
    }

    protected AContainer(Parcel source) {
        //read other AContainer fields
        source.readList(elements, A.class.getClassLoader());
        //read other AContainer fields
    }

    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        //write other AContainer fields
        dest.writeList(elements);
        //write other AContainer fields
    }
}

使用这些方法可能比 readTypedList()writeTypedList() 稍慢,但是来自 B 和 C 子类的特定数据也会被“封送”,而不仅仅是来自 A 抽象超类的字段(它将无法抽象化)。您可以从 B 和 C 中恢复正确的实例。


救命之答案。起初我找不到为什么在取消编组时它会崩溃,然后我也不知道该如何修复它。幸运的是,你的帖子让我两个小时的沮丧以微笑结束。谢谢! - Sufian
需要注意的是,在调用Parcel.readList()方法之前,必须先初始化elements - Henry

-2
public class A implements Parcelable{

       public A(){

       }

       public A(Parcel in){
            super(in);
           // read from parcel
           // number = in.readInt() etc
       }

       @Оverride
       public int describeContents(){
           return 0;
       }

       @Override
       public void writeToParcel(Parcel dest, int flags) {
           super.writeToParcel(out, flags);
          // write to parcel
          // out.writeInt
       }
       public static final Parcelable.Creator CREATOR = new Parcelable.Creator() {
           public Student createFromParcel(Parcel in) {
               return new A(in); 
           }

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

B和C也必须实现Parcelable接口


那么B和C的数据是如何编写的呢?那将是一个无用的Parcelable,还是我漏掉了什么? - Paul Woitaschek
super.writeToParcel(out, flags); 和 super(in) 在 B 和 C 中将确保从 A 读取数据。B 和 C 还需要实现 Parcelable。 - user840754
但是在出现问题的部分,当不知道类型时。我该怎么办?如果我调用你类的CREATOR,B和C不会受到影响,对吧? - Paul Woitaschek

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