Подтвердить что ты не робот

Вкладки для навигации Android: восстановление состояния просмотра фрагмента

Я пытаюсь понять, как сохранить состояние представления фрагмента, когда фрагменты используются в навигационных вкладках. В моих усилиях я столкнулся с двумя проблемами, из-за которых я не могу найти правильных решений.

У меня есть две вкладки: Tab1 и Tab2. Макет Tab1 определяется макетом FragmentA и Tab2, определяемым FragmentB. Я следил за приведенным здесь подходом: Добавление вкладок навигации

Первая проблема: Несмотря на то, что у моих представлений есть идентификаторы, их состояния не восстанавливаются полностью, когда фрагмент повторно подключен (после поворота переключателя табуляции). В частности: EditText с идентификатором действительно сохраняет свой введенный текст, но НЕ сохраняет его разрешенный статус. Также мои кнопки не сохраняются, если они включены или отключены, даже если у них есть идентификаторы. Я нашел два возможных решения этой проблемы:

  • При переключении вкладок используйте hide()/show() вместо attach()/detach().
  • in onPause() сохранить текущее состояние представления фрагмента в переменной экземпляра View фрагмента через getView(). В onCreateView(Bundle savedInstanceState) проверьте, не пустое это поле, и если это так, верните значение этого поля. Это решение кажется взломанным, и мне сказали, что он может также ввести утечку памяти в моем приложении.

Вторая проблема: Рассмотрим следующее взаимодействие с пользователем: Пользователь запускается в Tab1 и выполняет некоторые изменения, которые ставят состояние представления Tab1 в другое состояние, чем его состояние по умолчанию (и мы хотим, чтобы фрагмент сохранял это состояние просмотра с помощью табуляции и наклона устройства). Затем пользователь переходит к Tab2. Затем пользователь наклоняет свое устройство (все еще на Tab2). Затем пользователь переходит на Tab1 (при новой ориентации экрана). Теперь проблема заключается в следующем: когда пользователь изначально переходит из Tab1 в Tab2, фрагмент отсоединяется и, следовательно, его отбрасывается (хотя экземпляр фрагмента все еще живет). Когда пользователь затем наклоняет устройство, действие - и, тем самым, и FragmentA, и FragmentB, связанные с ним, - уничтожаются. Поскольку FragmentA в этот момент больше не имеет представления (помните: он был отсоединен), мы не можем сохранить состояние его элементов вида (например, какие кнопки включены/отключены) во время вызова FragmentA.onSaveInstanceState(Bundle savedInstanceState). Как восстановить состояние представления фрагмента в такой ситуации? Является единственным жизнеспособным решением для сохранения каждого отдельного элемента представления различных флагов статуса как SharedPreferences? Это кажется слишком сложным для такой "повседневной работы".

Я был повсюду в SO и в разных блогах, но не смог найти решение этой (конкретной) проблемы.

4b9b3361

Ответ 1

Проблема 1:

Android не сохраняет статус включенного просмотра по умолчанию. Кажется, что только вещи, которые непосредственно зависят от действий пользователя (без дополнительного кода), сохраняются. Для нормального просмотра информация не сохраняется, а для TextView, из которых EditText является подклассом, введенный текст сохраняется (если установлено freezesText).

Если вы хотите, чтобы все остальное было сохранено, вам придется сделать это самостоятельно. Здесь - вопрос с некоторыми ответами, которые показывают, как реализовать пользовательское сохранение состояния просмотра. Вы можете придерживаться прикрепления/отсоединения, если будете следовать этому подходу.

Проблема 2:

Вы правы в том, что Fragment.onSaveInstanceState(Bundle) можно вызвать после того, как ваше представление уже уничтожено. Однако это не то место, где вы должны сохранять свое состояние просмотра. Android вызовет View.onSaveInstanceState() прямо перед тем, как он уничтожит ваши представления при отсоединении фрагмента. Он сохраняет это состояние и возвращает его вам, когда вы снова присоединяете фрагмент. Это именно то, что происходит, когда вы переворачиваете между вкладками, как правило, без поворотов. Fragment.onSaveInstanceState(Bundle) не вызывается при отсоединении. Даже если вы повернете устройство, состояние просмотра, сохраненное в результате отсоединения, сохранится. Если вы реализуете View.onSaveInstanceState(), как указано выше, ваше состояние просмотра будет сохранено и восстановлено правильно, даже в сценарии Tab1-Tab2-rotate-Tab1.

Примечание: пример кода в документах, похоже, имеет некоторые проблемы, когда вы пытаетесь повернуть. Время жизни TabListener такое же, как и у Activity - при каждом повороте создается новый. Это означает, что он также теряет свою внутреннюю ссылку на фрагмент, каждый раз, когда вы вращаетесь. Добавленные фрагменты воссоздаются автоматически, поэтому TabListener не нужно пытаться создать новый экземпляр и добавить его после ротации. Вместо внутренней ссылки он должен просто попытаться найти фрагмент с соответствующим тегом в диспетчере фрагментов. После вращения он все равно будет существовать.

Другая проблема заключается в том, что выбранная вкладка не сохраняется, но это отмечено в нижней части примера. Вы можете сохранить это в Activity.onSaveInstanceState(Bundle).

Ответ 2

private ViewPager viewPager;
viewPager = (ViewPager) findViewById(R.id.pager);
mAdapter = new TabsPagerAdapter(getSupportFragmentManager());
viewPager.setAdapter(mAdapter);
viewPager.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {

        @Override
        public void onPageSelected(int position) {
            // on changing the page
            // make respected tab selected
            actionBar.setSelectedNavigationItem(position);
        }

        @Override
        public void onPageScrolled(int arg0, float arg1, int arg2) {
        }

        @Override
        public void onPageScrollStateChanged(int arg0) {
        }
    });
}

@Override
public void onTabReselected(Tab tab, FragmentTransaction ft) {
}

@Override
public void onTabSelected(Tab tab, FragmentTransaction ft) {
    // on tab selected
    // show respected fragment view
    viewPager.setCurrentItem(tab.getPosition());
}

@Override
public void onTabUnselected(Tab tab, FragmentTransaction ft) {
}