我正在尝试创建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>
是非静态的。
安德烈
答案 0 :(得分:16)
我在使用泛型的类上实现Parcelable时遇到了类似的问题,第一个问题与您遇到的问题相同:
因此我无法做公共静态最终Parcelable.Creator&gt; CREATOR因为MyParcelable是非静态的。
第二个是读取Parcelable对象,您需要访问由于type erasure无法从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
}
答案 1 :(得分: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
}
}
答案 2 :(得分:1)
将通用数据成员类名写入parcel,然后将其读回以创建其类加载器。例如,
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);
}
}
答案 3 :(得分: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)!!
}