ответы здесь уже велики, но не обязательно работать на пользовательских ViewGroups. Чтобы все пользовательские представления сохраняли свое состояние, вы должны переопределить onSaveInstanceState()
и onRestoreInstanceState(Parcelable state)
в каждом классе. Вам также необходимо убедиться, что все они имеют уникальные идентификаторы, независимо от того, надуты ли они из xml или добавлены программно.
Что я придумал, было замечательно, как ответ Kobor42, но ошибка осталась, потому что я добавлял Views в пользовательскую ViewGroup программно и не назначал уникальные идентификаторы.
Ссылка, совместно используемая mato, будет работать, но это означает, что ни один из отдельных представлений не управляет своим собственным состоянием - все состояние сохраняется в методах ViewGroup.
Проблема заключается в том, что при добавлении нескольких мастей этих представлений в макет, идентификаторы их элементов из xml больше не уникальны (если они определены в xml). Во время выполнения вы можете вызвать статический метод View.generateViewId()
, чтобы получить уникальный идентификатор для представления. Это доступно только для API 17.
Вот мой код из ViewGroup (он является абстрактным, и mOriginalValue является переменным типа):
public abstract class DetailRow<E> extends LinearLayout {
private static final String SUPER_INSTANCE_STATE = "saved_instance_state_parcelable";
private static final String STATE_VIEW_IDS = "state_view_ids";
private static final String STATE_ORIGINAL_VALUE = "state_original_value";
private E mOriginalValue;
private int[] mViewIds;
// ...
@Override
protected Parcelable onSaveInstanceState() {
// Create a bundle to put super parcelable in
Bundle bundle = new Bundle();
bundle.putParcelable(SUPER_INSTANCE_STATE, super.onSaveInstanceState());
// Use abstract method to put mOriginalValue in the bundle;
putValueInTheBundle(mOriginalValue, bundle, STATE_ORIGINAL_VALUE);
// Store mViewIds in the bundle - initialize if necessary.
if (mViewIds == null) {
// We need as many ids as child views
mViewIds = new int[getChildCount()];
for (int i = 0; i < mViewIds.length; i++) {
// generate a unique id for each view
mViewIds[i] = View.generateViewId();
// assign the id to the view at the same index
getChildAt(i).setId(mViewIds[i]);
}
}
bundle.putIntArray(STATE_VIEW_IDS, mViewIds);
// return the bundle
return bundle;
}
@Override
protected void onRestoreInstanceState(Parcelable state) {
// We know state is a Bundle:
Bundle bundle = (Bundle) state;
// Get mViewIds out of the bundle
mViewIds = bundle.getIntArray(STATE_VIEW_IDS);
// For each id, assign to the view of same index
if (mViewIds != null) {
for (int i = 0; i < mViewIds.length; i++) {
getChildAt(i).setId(mViewIds[i]);
}
}
// Get mOriginalValue out of the bundle
mOriginalValue = getValueBackOutOfTheBundle(bundle, STATE_ORIGINAL_VALUE);
// get super parcelable back out of the bundle and pass it to
// super.onRestoreInstanceState(Parcelable)
state = bundle.getParcelable(SUPER_INSTANCE_STATE);
super.onRestoreInstanceState(state);
}
}
Для тех, кто прибывает сюда, потому что это не работает при использовании фрагментов с библиотекой поддержки v4, я обратите внимание, что библиотека поддержки, похоже, не вызывает для вас представление onSaveInstanceState/onRestoreInstanceState; вы должны явно называть это самим из удобного места в FragmentActivity или Fragment. – magneticMonster
Обратите внимание, что в CustomView, к которому вы применяете это, должен быть установлен уникальный идентификатор, иначе они будут совместно использовать состояние друг с другом. SavedState хранится напротив идентификатора CustomView, поэтому, если у вас есть несколько CustomView с одним и тем же идентификатором или без id, то пакет, сохраненный в окончательном CustomView.onSaveInstanceState(), будет передан во все вызовы CustomView.onRestoreInstanceState(), когда взгляды будут восстановлены. –
Этот метод не работал для меня с двумя пользовательскими представлениями (один расширял другой). При восстановлении моего представления я продолжал получать ClassNotFoundException. Мне пришлось использовать подход Bundle в ответе Kobor42. – Chris