Разделяемый и наследование

Об этом несколько раз спрашивали здесь, на SO, но мой случай немного отличается.

У меня есть класс A, который реализует Parcelable. Класс A содержит некоторые данные членов, которые могут быть разделены. Он имеет свой собственный CREATOR и реализует writeToParcel(), describeContents() и конструктор, который принимает Parcel.

Существует класс B, который является продолжением класса A. Класс B имеет дополнительные данные членов, но ни один из них не нуждается в разделении. По сути, данные класса B такие же, как у класса A. Если я попытаюсь поместить B в Bundle, передать его другому действию и прочитать обратно, я получу исключение ClassCastException. Думаю, это ожидаемо.

После проб и ошибок, чтобы сделать класс B разделяемым, я должен реализовать по крайней мере две вещи:

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

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

public B(Parcel in) throws JSONException {
    super(in);
}

Так что моя забота заключается в следующем. Существует около полдюжины или более классов, которые расширяются от A, и все они имеют ту же проблему, что и B. Кажется глупым, что каждый из них должен добавлять свой собственный статический CREATOR и конструктор, который принимает Parcel, только чтобы передать его обратно к А. Все остальное идентично. Единственное, что отличает его, это имя класса. Это превосходит цель наследования в первую очередь.

Например, если есть другой класс C, расширяющий класс B, мне нужно сделать то же самое:

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

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

public C(Parcel in) throws JSONException {
    super(in);
}

Есть ли какие-то умные методы в Java для автоматизации этого процесса? Возможно, используя какой-то дженерик? Если нет другого пути, я мог бы просто удалить линию наследования и потребовать, чтобы каждый класс сам реализовал Parcelable.


person garbagecollector    schedule 09.10.2012    source источник
comment
Я немного опоздал, но вот как я справился с этим: stackoverflow.com/a/20018463/362298   -  person Ricardo    schedule 16.11.2013


Ответы (2)


Это немного сложно, но единственный способ, который я могу придумать навскидку, включает в себя отражение. При условии, что все подклассы имеют конструктор, который принимает Parcel, который затем вызывает super(parcel), вы можете сделать имя класса частью посылки - тогда в вашем метод createFromParcel для A:

public A createFromParcel(Parcel source) {
    Class clazz = Class.forName(source.readString());
    Class[1] paramTypes = { Parcel.class }; 
    Constructor ctor = clazz.getConstructor(paramTypes);
    A myA = (A) ctor.newInstance(source);
    return myA;
}

Обратите внимание, что это было написано в основном спонтанно и может потребовать некоторой настройки перед запуском (я точно знаю, что в нем отсутствуют проверенные обработчики исключений), но, надеюсь, идея ясна.

person JRaymond    schedule 09.10.2012

Я реализовал решение, описанное JRaymond, и оно работает. Это немного сложно, так как требует некоторого размышления, но я надеюсь, что это поможет кому-то еще. Теперь любой класс, который может быть разделен, должен расширять этот класс GlobalParcelable, который реализует возможность разделения.

https://github.com/awadalaa/Android-Global-Parcelable

person Alaa Awad    schedule 27.09.2013