Как сериализовать список пользовательских объектов и восстановить его onRestoreInstanceState в Android?

Привет всем, у меня есть пользовательский объект MasterWithValue (объект со значением и списком созданных мной объектов Detail), который расширяет класс Master (у которого есть только свойство name).

Это класс MasterWithValue:

public class MasterWithValue extends Master {

private String value;
private List<Detail> detailList;

public MasterWithValue(String masterName, String masterValue) {
    super(masterName);
    this.value = masterValue;
    this.detailList = new ArrayList<Detail>();
}

@Override 
public int getViewType() {
    return super.getViewType();
}

@Override
public View getView(LayoutInflater inflater, View convertView) {
    View view;
    if (convertView == null) {
        view = inflater.inflate(R.layout.statistics_rowlist_master, null);
    }
    else {
        view = convertView;
    }

    TextView MasterEntryName = (TextView) view.findViewById(R.id.statistics_master_name);
    TextView MasterEntryValue = (TextView) view.findViewById(R.id.statistics_master_value);

    MasterEntryName.setText(super.name);
    MasterEntryValue.setText(this.value);

    return view;
}

public String getMasterValue() {
    return value;
}

public List<Detail> getDetailList() {
    return this.detailList;
}

public void addDetailToMaster(Detail detail) {
    this.detailList.add(detail);
}

}

В методе onSaveInstanceState() у меня есть этот код:

@Override
protected void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);
    outState.putSerializable("master_detail_list", (ArrayList<MasterWithValue>)   
      MasterAndDetailStatistics);
}

Где MasterAndDetailStatistics — это список.

Теперь в onRestoreInstanceState я попробовал этот код:

@Override
protected void onRestoreInstanceState(Bundle savedState) {
    super.onRestoreInstanceState(savedState);

    MasterAndDetailStatistics = (List<MasterWithValue>) savedState.getSerializable("master_detail_list");

}

By Я получаю предупреждение о безопасности типов: Безопасность типов: Unchecked cast from Serializable to List Как я могу это проверить? Я читал, что должен реализовать интерфейс Parcable, но я новичок в Android и понятия не имею, как это сделать. Что я должен делать?


person tonix    schedule 20.03.2014    source источник


Ответы (1)


Есть много примеров того, как можно реализовать посылки. Вот канонический. Вот ответ от SO.

По сути, вы реализуете метод public void writeToParcel(Parcel out, int flags), в котором вы записываете все поля, которые хотите сохранить, в значение out.

Затем реализуйте анонимную реализацию Parcelable.Creator, параметризованную с помощью вашего класса. Эта анонимная реализация должна называться CREATOR.

Наконец, создайте приватный конструктор следующим образом: private MyParcelable(Parcel in). Где вы читаете все значения, которые вы написали в out, обратно в поля вашего объекта в in.

Тогда вам также нужно сделать детали делимыми! О радость!

Это должно выглядеть так:

public class MasterWithDetails implements Parcelable {
    private String value;
    private List<Detail> detailList;

    public int describeContents() {
        return 0;
    }

    public void writeToParcel(Parcel out, int flags) {
        out.writeString(value);
        out.writeString(getName());
        out.writeTypedList(detailList); //don't forget to make Detail parcelable too!
    }

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

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

    private MasterWithDetails(Parcel in) {
        value = in.readString();
        setName(in.readString());
        detailList = in.createTypedArrayList(Detail.CREATOR);
    }
}
person CorayThan    schedule 20.03.2014
comment
Спасибо за ответ. Если класс MasterWithValue расширяет класс Master, они должны вместе реализовывать интерфейс Parcelable? Я имею в виду, что я реализую интерфейс Parcelable в классе Master, а затем в MasterWithValue я переопределяю эти методы, чтобы также сохранить значение объекта MasterWithValue, поскольку MasterWithValue имеет поле значения, которого нет в классе Master. Я прав? - person tonix; 22.03.2014
comment
Я также получаю это, когда пытаюсь вызвать writeTypedArrayList(): метод writeTypedArrayList(List‹Detail›) не определен для типа Parcel. Возможно, вы собирались использовать writeTypedList(detailList)? - person tonix; 22.03.2014
comment
Да, наверное, я торопился и имел в виду writeTypedList. Для класса-потомка вам нужно будет переопределить метод writeToParcel (хотя при вызове super.writeToParcel вам не нужно будет дублировать какую-либо логику). Конструктор является закрытым, поэтому его нельзя переопределить или вызвать, и его необходимо дублировать. Поле CREATOR общедоступно и статично, поэтому его не следует изменять. Честно говоря, packageable выглядит довольно уродливо, когда вы используете его с наследованием. Конечно, я думаю, что это выглядит некрасиво в первую очередь. (Обычно я предпочитаю просто сериализовать свои классы как строки (с JSON) или байты.) - person CorayThan; 22.03.2014
comment
Спасибо, это работает! Спасибо за объяснение, очень понятно и просто! - person tonix; 22.03.2014