Как правильно реализовать onRestoreInstanceState () для подкласса DialogPreference?


Я реализую свой собственный подкласс DialogPreference, который имеет панель поиска, используемую для сохранения целого числа. Я немного запутался в том, что нужно сделать в onSaveInstanceState() и onRestoreInstanceState(). В частности, нужно ли обновить виджет пользовательского интерфейса, с которым взаимодействует пользователь (в моем случае виджет панели поиска) в onRestoreInstanceState()?

Причина, по которой я запутался, заключается в том, что статья API doc здесь говорит вам сделать это:

@Override
protected Parcelable onSaveInstanceState() {
    final Parcelable superState = super.onSaveInstanceState();
    if (isPersistent()) {
        return superState;
    }

    final SavedState myState = new SavedState(superState);
    myState.value = mNewValue; //<------------ saves mNewValue
    return myState;
}

@Override
protected void onRestoreInstanceState(Parcelable state) {
    if (state == null || !state.getClass().equals(SavedState.class)) {
        super.onRestoreInstanceState(state);
        return;
    }

    SavedState myState = (SavedState) state;
    super.onRestoreInstanceState(myState.getSuperState());
    mNumberPicker.setValue(myState.value); //<------------ updates the UI widget, not mNewValue!
}

Но глядя на источник для некоторых официальных классов предпочтений Android (EditTextPreference и ListPreference), виджет пользовательского интерфейса не обновляется в onRestoreInstanceState(). Только базовое значение предпочтения (в приведенном выше примере это будет mNewValue).

Вот соответствующий источник для EditTextPreference:

@Override
protected Parcelable onSaveInstanceState() {
    final Parcelable superState = super.onSaveInstanceState();
    if (isPersistent()) {
        return superState;
    }

    final SavedState myState = new SavedState(superState);
    myState.value = getValue(); //<---- saves mValue
    return myState;
}

@Override
protected void onRestoreInstanceState(Parcelable state) {
    if (state == null || !state.getClass().equals(SavedState.class)) {
        super.onRestoreInstanceState(state);
        return;
    }

    SavedState myState = (SavedState) state;
    super.onRestoreInstanceState(myState.getSuperState());
    setValue(myState.value); //<---- updates mValue, NOT the UI widget!
}

Итак, каков консенсус? Где я должен обновить виджет пользовательского интерфейса (если я вообще должен его обновить...)?

1 8

1 ответ:

Хорошо, после некоторых экспериментов, похоже, что обновление виджета пользовательского интерфейса внутри onRestoreInstanceState() - это не путь, потому что он всегда кажется null в этой точке. Я не знаю, почему они это предлагают. Возможно, Вам придется это сделать, если предпочтение отдается подклассам, но существуют различные правила, которым нужно следовать при создании подклассов DialogPreference...? Это, по крайней мере, объяснило бы, почему ListPreference и EditTextPreference не делают этого, потому что они подкласс DialogPreference.

На самом деле, из того, что я нашел, UI виджет не нуждается в обновлении вообще! Он должен иметь свои собственные методы сохранения / восстановления, которые управляют его состоянием для вас. Например, вот отрывок подкласса DialogPreference, который я сделал с виджетом SeekBar в нем:

@Override
protected Parcelable onSaveInstanceState() {
    final Parcelable superState = super.onSaveInstanceState();

    final SavedState myState = new SavedState(superState);
    myState.maxValue = getMaxValue(); //<---- saves mMaxValue
    myState.value = getValue(); //<---- saves mValue
    return myState;
}

@Override
protected void onRestoreInstanceState(Parcelable state) {
    if (state == null || !state.getClass().equals(SavedState.class))
    {
        super.onRestoreInstanceState(state);
        return;
    }

    SavedState myState = (SavedState) state;
    setMaxValue(myState.maxValue); //<---- updates mMaxValue
    setValue(myState.value); //<---- updates mValue
    super.onRestoreInstanceState(myState.getSuperState());
}

Как вы можете видеть, я никогда не обновляю виджет панели поиска в любом месте. Панель поиска сохранит / восстановит свое состояние сама по себе!

Вы также заметите, что есть некоторые незначительные отклонения от того, что предлагается в документах разработчика Android. Я не проверяю, если DialogPreference является постоянным перед сохранением состояния, потому что тогда свойства mValue и mMaxValue не будут сохранены, если это так. Я также вызываю super.onRestoreInstanceState() прямо в конце, так как я обнаружил, что он никогда не работает, когда он вызывается ранее.

Это пока только мои выводы. Я не уверен, что это правильный путь, но то, что у меня есть выше, кажется, работает.

UPDATE: @whatyouhide хочет знать, как выглядят методы setValue и setMaxValue в моем подклассе DialogPreference. Вот они:

public void setValue(int value)
{
    value = Math.max(Math.min(value, mMaxValue), mMinValue);

    if (value != mValue)
    {
        mValue = value;
        persistInt(value);
        notifyChanged();
    }
}

public void setMaxValue(int maxValue)
{
    mMaxValue = maxValue;
    setValue(Math.min(mValue, mMaxValue));
}