在多态数组上实现Parcelable接口

4

我有一个名为ItinerarySegment的类型数组,这个类型有子类:WalkSegmentBusSegment等。

public interface ItinerarySegment
{

}

public class WalkSegment implements ItinerarySegment
{

}

public class BusSegment implements ItinerarySegment
{

}

我制作 ItinerarySegment 的数组时应该遵循哪种策略才好? 这里最主要的问题是后续如何使用 createTypedArray 方法来重新构建数组(这个方法由 writeTypedArray 方法准备)。
在其中,createTypedArray 方法需要一个 Creator 字段参数。问题在于...Creator 字段应该在哪里定义? (在 ItinerarySegmentWalkSegment 还是 BusSegment 中?)。
public static final Creator<Typename> CREATOR = new Parcelable.Creator<Typename>()
{
    public Typename createFromParcel(Parcel in)
    {
        return new Typename(in);
    }

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

};

如果我将ItinerarySegment定义为抽象类并定义Creator字段的方法,那么后续子类的数据将会丢失,因为它们的构造函数都没有用Parcel参数调用,而是调用了ItinerarySegment的构造函数。
constructor(Parcel in);

如果我让WalkSegment定义Creator字段,那么BusSegment会有问题。
需要澄清吗?
1个回答

4
为了使用writeTypedArray()createTypedArray(),你需要将ItinerarySegment变为abstract class而不是interfaceItinerarySegment需要实现Parcelable并定义一个CREATOR,在取消封送Parcel并创建新对象时会调用它。派生类还需要实现writeToParcel()describeContents()CREATOR方法。

注意:因为writeTypedArray()并不会将对象的类型写入Parcel,所以你需要自己完成这一步骤。下面有两种可能的方式:

  1. 每个派生类的writeParcel()方法需要在最开始写入某些内容,以标识它的类型(Stringint值)。

  2. 每个派生类的writeParcel()方法需要在写入任何内容之前先调用super.writeToParcel()。在ItinerarySegment.writeToParcel()方法中,你可以确定它是哪个派生类的类型,并写入内容以标识其类型(Stringint值)。

ItinerarySegment中的CREATOR需要首先从Parcel读取标识符,然后根据标识符确定要实例化哪种类型的对象。然后它将调用相应对象的CREATOR来实际实例化对象,并将其返回给调用者。

这基本上就像一个对象工厂,基类知道如何实例化自己的不同派生类。

所有这些的缺点是抽象基类必须知道所有派生类。我想你也可以通过使所有派生类调用基类中的静态方法并传递它们的“类型”和CREATOR来动态完成,则基类将把它们存储在数组中以便按需使用。

这一切都可以做到,但非常复杂。

作为替代方案,你可以使用writeParcelableArray()readParcelableArray(),其中每个对象的类名都写入了Parcel,以便在取消封送时知道调用哪个CREATOR

在我看来,只有当数组中的所有对象都是同一类的实例,并且您将它们写入Parcel时,才需要使用writeTypedArray()createTypedArray(),并且数量超过了一小部分。在这种情况下,您可以避免为每个对象编写类名而产生的开销,因为您知道它们都是相同的。在这种情况下,您不需要像上面描述的那样费尽心思,因为您事先知道所有对象的类型(没有多态类型)。

我意识到这个答案可能已经晚了一年以上,但无妨。也许它会帮助其他人 ;-)


2
我意识到这条评论已经晚了一年以上 :-) 但是,是的,你的答案很有帮助。我一直在想Java如何将多态包解包成正确的类型...现在我明白它并没有这样做。 :-( 这很遗憾,但是你建议的工厂方法应该可以解决问题。 - dajames

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