Android - давление памяти падает с помощью ViewPager > Фрагменты> Действия

Я использую библиотеку поддержки v4 в нашем приложении, и у меня есть пошаговый процесс в приложении, который работает нормально при нормальных обстоятельствах. Однако у нас есть требование, чтобы все работало, а не зависало в ситуациях с нехваткой памяти. Поэтому я использую библиотеку SetAlwaysFinish, чтобы помочь с этим ( https://github.com/bricolsoftconsulting/SetAlwaysFinish). В точных областях было очень полезно обнаруживать и обрабатывать подобные ситуации, но я столкнулся с ситуацией, которая поставила меня в тупик. Имейте в виду, что это нормально работает при нормальных обстоятельствах, но я явно тестирую с setAlwaysFinish = ON.

Вот мои настройки: у меня есть класс "ProcessActivity", в котором размещается макет для ViewPager. ViewPager имеет набор адаптеров, который содержит мой список фрагментов, которые будут охватывать процесс. Это в методе onCreate():

ProcessActivity:

createSteps();  // this creates/populates the ArrayList "processSteps" with Fragments
theAdapter = new ProcessAdapter(this, processSteps); // the ProcessAdapter class extends FragmentStatePagerAdapter, with an additional list of Fragment steps
theViewPager.setAdapter(theAdapter);

Есть и другие части, но это основа его настройки. Во время одного из шагов фрагмента мне действительно нужно "оторваться" от процесса шага и временно перейти к действию, чтобы выполнить некоторую логику (а затем впоследствии вернуться к процессу шага). Я делаю это следующим образом с помощью ForResult, поскольку мне нужно иметь возможность обрабатывать действие OK/ Отмена в действии после его завершения:

Step4Fragment:

Intent intent = new Intent(getActivity(), ThePushActivity.class);
intent.putExtra(blah..);
startActivityForResult(intent, THE_REQCODE);

Как только он выдвигается в это представление, иногда вызывается метод onDestroy() как ProcessActivity, так и Step4Fragment (из-за AlwaysFinish). Иногда кажется, что он работает нормально, и он вызывает процесс пошагового фрагмента. Но обычно он вызывает метод onDestroy() ProcessActivity, а затем повторно вызывает метод onCreate() с заполнением состояния сохраненного экземпляра пакета. Это вызовет код создания шага, приведенный выше, и переводит приложение в причудливое состояние, в котором отображается последний шаг, на котором был показан пользователь, но за кулисами он фактически находится на первом шаге (в этот момент фрагменты находятся вне ударить и отключить), и сбой неизбежно происходит. Кажется, что в этот момент Step4Fragment полностью разделен и где-то потерпит крах, если вы попытаетесь что-либо сделать, даже если кажется, что он был восстановлен правильно

Есть мысли о лучших способах решения этой проблемы? Я думаю, что это хорошо, если я найду способ даже просто сбросить настройки, чтобы пользователь мог вернуться к первому шагу процесса, если возникла проблема с памятью. Тем не менее, все мое беспокойство, конечно, крушение.

Дайте мне знать, если мне нужно предоставить более подробную информацию. Заранее благодарю за любую помощь!

ОБНОВЛЕНИЕ № 1: Просто быстрое обновление, которое я заметил, что фрагменты восстанавливаются и инициализируются, и он правильно попадает в метод onActivityResult() "текущего" фрагмента и делает то, что ему нужно делать правильно. Кажется, что разъединение находится в базовом классе ProcessActivity, следуя одному из этих сценариев. Макет ViewPager отображается правильно, но все, что находится за пределами ViewPager, неверно (т.е. это указывает на то, что он находится на 1-м шаге процесса, когда он должен указывать, что он на 4-м шаге, а кнопки навигации отображаются на 1-м шаге). а не 4-й).

Я предполагаю, что мне нужно как-то правильно установить эти элементы вручную. Углубляясь в это, я могу упустить фрагменты кода, которые необходимы для того, чтобы кто-то активно помогал с этим. Если бы я мог как-то получить доступ к состоянию поля ViewPager, которое содержит возможность получить "показанный в данный момент фрагмент", до того, как был вызван весь этот onDestroy()/onCreate(), возможно, из комплекта saveInstanceState? Это, вероятно, решит мою проблему. Но после проверки этой связки после отладки я в основном вижу только сами фрагменты и их соответствующие состояния. Я буду продолжать копать, хотя.

Независимо от этого, пожалуйста, дайте мне знать, если у кого-нибудь есть какие-либо идеи о том, как следует правильно делать подобные вещи (на высоком уровне, конечно).

ОБНОВЛЕНИЕ № 2 Я вижу, что даже несмотря на то, что "текущий" фрагмент, кажется, правильно инициализирован, и представление показывает правильно, все отсоединено. Я не могу вызывать какие-либо методы для getResources() или getActivity() и т. Д. Я действительно смог заставить 'ProcessActivity' работать 'должным образом, основываясь на сохранении индекса шага (int) в пакете saveInstanceState, а затем перезагрузить пользовательский интерфейс элементы вокруг него. Тем не менее, у меня все еще есть этот блокировщик с текущим фрагментом, отсоединенным от Activity, хотя он, похоже, был обновлен должным образом.

ОБНОВЛЕНИЕ № 3 Когда я следую указаниям этого поста: ViewPager и фрагменты - как правильно сохранить состояние фрагмента? Я получаю немедленное исключение, когда я пытаюсь сделать первый putFragment(). Исключение: "IllegalStateException: Fragment Step4Fragment в настоящее время отсутствует в FragmentManager". Я думаю, что это может быть связано с тем фактом, что я держу только один фрагмент слева и один фрагмент справа "активный" в любое время (то есть offScreenPageLimit).

2 ответа

Решение

Оказывается, что решение этого было похоже на решение, представленное в этом посте: ViewPager и фрагменты - как правильно сохранить состояние фрагмента?

У меня было несколько вещей, которые нужно было изменить. Во-первых, мне нужно было перемещать фрагменты в поля, а не на временные переменные. Во-вторых, мне нужно было избегать создания новых фрагментов каждый раз в onCreate(). Вместо этого он должен попытаться извлечь их из saveInstanceState следующим образом:

fragment1 = (Fragment1Step) getSupportFragmentManager().getFragment(savedInstanceState, Fragment1Step.class.getName());
fragment2 = (Fragment2Step) getSupportFragmentManager().getFragment(savedInstanceState, Fragment2Step.class.getName());
etc...

и затем сразу после этого у меня есть последующие проверки для каждого из них; если они имеют значение null (то есть поступают заново, а не из сохраненного экземпляра), то они будут созданы как новые:

if (fragment1 == null) {
    fragment1 = new Fragment1Step();
} 
if (fragment2 == null) {
    fragment2 = new Fragment2Step();
} 

Конечно, чтобы это работало, их также следует сохранить в методе onSaveInstanceState():

try {
    getSupportFragmentManager().putFragment(outState, Fragment1Step.class.getName(), fragment1);
} catch (Exception e) {
    // do nothing
}
try {
    getSupportFragmentManager().putFragment(outState, Fragment2Step.class.getName(), fragment2);
} catch (Exception e) {
    // do nothing
}
etc...

Причина, по которой у меня это есть в блоках try/catch, заключается в том, что у нашего ViewPager offScreenPageLimit только 1, поэтому некоторые из них будут вызывать исключения при вызове putFragment(), если они в данный момент отсутствуют в "активном" стеке фрагментов показывается.

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

Вы уверены, что ваш фрагмент не восстанавливается?

Все подклассы Fragment должны включать открытый пустой конструктор. Каркас часто создает экземпляр класса фрагмента, когда это необходимо, в частности, во время восстановления состояния, и должен иметь возможность найти этот конструктор, чтобы создать его экземпляр. Если пустой конструктор недоступен, в некоторых случаях во время восстановления состояния возникает исключение времени выполнения.

Другие вопросы по тегам