FragmentActivity onSaveInstanceState не получает вызов

Я видел несколько похожих вопросов о onSaveInstanceState, которые не вызываются для Fragment s, но в моем случае Fragment работают нормально, это основной FragmentActivity, который имеет проблемы.

Соответствующий код выглядит довольно просто:

public class MyFActivity extends FragmentActivity implements ActionBar.TabListener { 
    String[] allValues; // data to save

    @Override
    protected void onSaveInstanceState (Bundle outState) {
        Log.d("putting it!", allValues.toString());
        outState.putStringArray("allValues", allValues);
        super.onSaveInstanceState(outState);
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        if (savedInstanceState != null) {
            allValues = savedInstanceState.getStringArray("allValues");
            Log.d("getting it!", allValues.toString());
        }
    }
}

При приостановке действия (с помощью кнопки "Назад" ) onSaveInstanceState никогда не вызывается, и, следовательно, savedInstanceState всегда null в рамках метода onCreate при возобновлении приложения. Я попытался добавить блок следующим образом:

@Override
public void onPause() {
    super.onPause();
    onSaveInstanceState(new Bundle());      
}

который был предложен в https://stackoverflow.com/a/14195202/362657, но в то время как onSaveInstanceState затем получает вызов, savedInstanceState остается null внутри метода onCreate. Что мне не хватает?

Ответы

Ответ 1

Проблема в том, что вы не понимаете, как работает onSaveInstanceState. Он предназначен для сохранения состояния Activity/Fragment в случае, когда ОС необходимо уничтожить его по соображениям памяти или изменениям конфигурации. Это состояние затем возвращается в onCreate, когда Activity/Fragment возвращается/перезапускается.

В Fragment все их обратные вызовы жизненного цикла напрямую привязаны к их родительскому Activity. Поэтому onSaveInstanceState вызывается в Fragment, когда его родительский Activity имеет onSaveInstanceState.

При приостановке действия (с помощью кнопки "Назад" ) onSaveInstanceState никогда не вызывается, и, следовательно, savedInstanceState всегда остается в пределах метода onCreate при возобновлении приложения.

При нажатии назад пользователь уничтожает Activity и, следовательно, его дочерние элементы Fragment s, поэтому нет причин для вызова onSaveInstanceState, так как экземпляр уничтожается. Когда вы снова открываете Activity, это новый экземпляр без сохранения состояния, поэтому Bundle, прошедший в onCreate, null. Это ведет себя точно так же, как и предусмотрено. Однако попробуйте повернуть устройство или нажать кнопку "домой", после чего вы увидите, что Activity и его дочерние элементы Fragment имеют onSaveInstanceState, а затем возвращены в onCreate при возврате.

Добавленный хак, напрямую вызывающий onSaveInstanceState(new Bundle()); внутри onPause, является очень плохой практикой, так как вы должны никогда вызывать обратные вызовы жизненного цикла напрямую. Это может привести ваше приложение к незаконным состояниям.

Если вы действительно хотите, чтобы ваши данные сохранялись за пределами вашего приложения, я предлагаю вам изучить SharedPreferences или databases для более продвинутых данных. Затем вы можете сохранить свои постоянные данные в onPause() или при каждом изменении.

Надеюсь, что это поможет.

Ответ 2

В обновлении принятого ответа:

Фрагмент onSaveInstanceState может быть вызван, если вы используете ViewPager с FragmentStatePagerAdapter (а не FragmentPagerAdapter)

FragmentStatePagerAdapter

Эта версия пейджера более полезна, когда имеется большое количество страниц, больше похоже на просмотр списка. Когда страницы не видны пользователю, их весь фрагмент может быть уничтожен, сохраняя сохраненное состояние этого фрагмента. Это позволяет пейджеру удерживать гораздо меньшую память, связанную с каждой посещенной страницей, по сравнению с FragmentPagerAdapter за счет потенциально большего количества накладных расходов при переключении между страницами.

И не забывайте:

При использовании FragmentPagerAdapter хост ViewPager должен иметь действительный набор идентификаторов.