18

我正在尝试创建public class MyClass<T extends Parcelable> implements Parcelable. 我在实施Parcelable. 是否可以创建一个实现的泛型类Parcelable?(请注意,它T是有界的,因此它也必须实现Parcelable)。

Parcelable 接口需要一个静态变量,我遇到了麻烦:public static final Parcelable.Creator<MyParcelable> CREATOR. 因此我不能这样做public static final Parcelable.Creator<MyClass<T>> CREATOR,因为MyParcelable<T>它是非静态的。

安德烈

4

4 回答 4

23

我在使用泛型的类上实现 Parcelable 时遇到了类似的问题,第一个问题与您遇到的相同:

因此我不能做 public static final Parcelable.Creator> CREATOR 因为 MyParcelable 是非静态的。

第二个是读取 Parcelable 对象,您需要访问由于类型擦除ClassLoader而无法获取的对象。T

下面的类是我在生产中使用的类的改编,它克服了这两个问题。注意:我没有专门测试过这个类,所以如果你有任何问题,请告诉我。

public class TestModel<T extends Parcelable> implements Parcelable {

private List<T> items;
private String someField;

public List<T> items() {
    return items;
}

public void setItems(List<T> newValue) {
    items = newValue;
}

public String someField() {
    return someField;
}

public void setSomeField(String newValue) {
    someField = newValue;
}

//region: Parcelable implementation

public TestModel(Parcel in) {
    someField = in.readString();

    int size = in.readInt();
    if (size == 0) {
        items = null;
    }

    else {

        Class<?> type = (Class<?>) in.readSerializable();

        items = new ArrayList<>(size);
        in.readList(items, type.getClassLoader());
    }
}

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

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

    if (items == null || items.size() == 0)
        dest.writeInt(0);

    else {
        dest.writeInt(items.size());

        final Class<?> objectsType = items.get(0).getClass();
        dest.writeSerializable(objectsType);

        dest.writeList(items);
    }
}

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

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

//endregion
}
于 2015-08-13T04:08:50.097 回答
5

将通用数据成员类名写入包中,然后将其读回以创建其类加载器。例子,

public class MyClass<T> implements Parcelable {
    T data;

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeString(data.getClass().getName());
        dest.writeParcelable((Parcelable) data, 0);
    }

    private MyClass(Parcel in) {
        final String className = in.readString();
        try {
            data = in.readParcelable(Class.forName(className).getClassLoader());
        } catch (ClassNotFoundException e) {
            Log.e("readParcelable", className, e);
        }
    }
于 2017-03-07T16:54:39.760 回答
2

是的你可以。您只需要在构建子类对象期间存储类名或类加载器,然后您可以在 Parcelable 的读/写操作期间传递它。

分步说明:

步骤 1。存储从您的 Generic 类扩展的类名,如下所示:

public abstract class GenericClass<T> implements Parcelable {
    private String className;

步骤 2。从泛型类扩展的任何类都必须在构造过程中指定类名,如下所示:

public class MyClass extends GenericClass<MyClass> {

    public MyClass () {
        super();
        setClassName(MyClass.class.getName()); // Generic class setter method
    }

步骤 3。在您的通用类中,您可以像这样读取/写入您的类名到 getClassLoader() :

public abstract class GenericClass<T> implements Parcelable {
    private String className;
    T myGenericObject;

    protected MyClass (Parcel in) {
        super(in);
        this.className = in.readString();
        ClassLoader classLoader;
        try {
            classLoader = Class.forName(this.className).getClassLoader();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        myGenericObject = in.readParcelable(classLoader);
        //... Other class members can go here
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        super.writeToParcel(dest, flags);
        dest.writeString(className);
        //... Other class members can go here
    }

}

于 2016-07-04T12:17:20.467 回答
0

根据上面的答案,为此创建了扩展功能。

fun <T : Parcelable> Parcel.writeGenericParcelable(data: T, flags: Int) {
    writeString(data::class.java.name)
    writeParcelable(data, flags)
}

fun <T : Parcelable> Parcel.readGenericParcelable(): T {
  val className = readString()!!
  val classNameLoader = Class.forName(className).classLoader
  return readParcelable(classNameLoader)!!
}
于 2021-03-05T11:32:10.623 回答