4

我有一个名为 类型的数组ItinerarySegment,并且这种类型有子类:WalkSegmentBusSegment

public interface ItinerarySegment
{

}

public class WalkSegment implements ItinerarySegment
{

}

public class BusSegment implements ItinerarySegment
{

}

ItinerarySegment制作parcelable数组时应该遵循什么样的策略?这里主要关心的是稍后通过createTypedArray方法(由writeTypedArray方法准备)重新构造数组时如何使用它。

其中createTypedArray方法采用Creator字段参数。问题出在这里...应该在哪里定义Creator字段?(在ItinerarySegmentWalkSegmentBusSegment? 中)。

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会有问题。

需要任何澄清吗?

4

1 回答 1

4

为了做到这一点writeTypedArray()createTypedArray()你需要制作ItinerarySegment一个abstract class,而不是一个interfaceItinerarySegment将需要实现Parcelable,并且需要CREATOR定义一个被调用来解组Parcel和创建新对象的定义。派生类也需要实现方法writeToParcel()describeContents()并且CREATOR.

注意:因为writeTypedArray()不会将对象的类型写入 中Parcel,所以您需要自己执行此操作。这里有两种可能的方法:

  1. writeParcel()每个派生类的方法都必须Parcel在最开始时写一些东西来标识它的类型(aStringint值)。

  2. writeParcel()每个派生类的方法都必须super.writeToParcel()在向Parcel. 在该ItinerarySegment.writeToParcel()方法中,您可以确定它是什么类型的派生类,并将一些东西写入Parcel标识其类型(aStringint值)的东西。

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

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

所有这些的缺点是抽象基类必须知道它的所有派生类。我想您也可以动态地执行此操作,方法是让所有派生类调用基类中的静态方法,传递其“类型” and CREATOR,然后基类将其存储在一个数组中以根据需要使用。

都是可行的,但相当复杂。

作为替代方案,您可以使用writeParcelableArray()and readParcelableArray(),将每个对象的类名写入 ,Parcel以便它知道CREATOR在解组时调用哪个。

恕我直言,唯一使用的时间writeTypedArray()createTypedArray()当数组中的所有对象都是同一个类的实例时,并且您将其中的多个对象写入Parcel. 在这种情况下,您可以节省将类名写入Parcel每个对象的开销,因为您知道它们都是相同的。在这种情况下,您不需要经历我上面描述的所有痛苦,因为您事先知道所有对象的类型(没有多态类型)。

我意识到这个答案可能晚了一年多,但到底是什么。也许它会帮助别人;-)

于 2015-02-08T12:14:28.980 回答