Можно ли отправить общий класс?

Я пытаюсь создать public class MyClass<T extends Parcelable> implements Parcelable. У меня возникли проблемы с реализацией Parcelable. Можно ли создать общий класс, который реализует Parcelable? (Заметим, что T ограничен, так что он также должен реализовывать Parcelable).

У меня возникает проблема с тем, что для интерфейса Parcelable требуется переменная static: public static final Parcelable.Creator<MyParcelable> CREATOR. Таким образом, я не могу сделать public static final Parcelable.Creator<MyClass<T>> CREATOR, потому что MyParcelable<T> нестатический.

Андре

Ответ 1

У меня были аналогичные проблемы с реализацией Parcelable в классе с общим, первый вопрос был таким же, как и то, что вы испытывали:

Таким образом, я не могу сделать публичный статический окончательный 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
}

Ответ 2

Да, вы можете. Вам просто нужно сохранить имя класса или загрузчик классов во время построения вашего объекта подкласса, а затем вы можете передать его во время операции чтения/записи в произвольном экземпляре.

Пошаговые инструкции:

Шаг 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
    }

}

Ответ 3

Запишите имя класса элемента данных в парцеллу, а затем прочитайте его, чтобы создать свой загрузчик классов. Пример,

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);
        }
    }