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

Невозможно использовать Fragment.setRetainInstance() в качестве замены Activity.onRetainNonConfigurationInstance()

Согласно документации API Android, Activity.onRetainNonConfigurationInstance() устарел в пользу Fragment.setRetainInstance().

Однако я столкнулся с двумя отдельными ситуациями, когда Fragment.setRetainInstance() не представляется возможным использовать.

  • Если фрагмент содержит WebView. Согласно Diane Hackborne, вы не можете повторно использовать WebView для изменений конфигурации. Я думаю, это означает, что вам нужно разрешить фрагментации сбрасывать и воссоздавать WebView при повороте экрана и использовать WebView.saveState() и WebView.restoreState(), чтобы восстановить состояние веб-представления.

  • Если фрагмент принадлежит макету, который больше не существует после изменения конфигурации, когда FragmentManager пытается восстановить фрагмент, он будет бросать:

    java.lang.IllegalArgumentException: No view found for id 0x7f060091 for fragment
    

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

Итак, если вы создаете приложение на основе фрагментов и вам нужно сохранить данные (например, ссылки на запуск AsyncTasks) между изменениями конфигурации, и вы не можете использовать Fragment.setRetainInstance(), и нет Fragment.onRetainNonConfigurationInstance(), что лучше всего подходит?

4b9b3361

Ответ 1

Даже если вы используете Fragment.setRetainInstance(), фрагмент по-прежнему будет разрушать его представление и воссоздавать его после изменения конфигурации. То есть в этой последовательности будут вызываться onDestroyView() и onCreateView(). Убедитесь, что старые ссылки на WebView недействительны в onDestroyView(). Вам не нужно беспокоиться о повторном использовании WebView - новый WebView будет воссоздан с правильным контекстом Activity. Это несколько неуместно, потому что для сохранения состояния WebView вам все равно нужно вызвать WebView.saveState(Bundle) в Fragment.onSaveInstanceState(Bundle) и WebView.restoreState(Bundle) в Fragment.onViewCreated(Bundle). Это означает, что Fragment.setRetainInstance() по-прежнему совместим с использованием WebView.

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

В любом случае, вместо того, чтобы сделать один фрагмент, обрабатывающий как пользовательский интерфейс, так и загрузку AsyncTask, вы можете разделить их на два фрагмента - тот, у которого есть AsyncTask, вообще не нужно прикреплять к иерархии представлений и может быть установлен быть сохраненным экземпляром. Это упрощает ваши проблемы и делает более чистую архитектуру. Когда AsyncTask завершается, вам нужно вернуться к фрагменту пользовательского интерфейса, чтобы доставить результаты (например, findFragmentById/Tag, setTargetFragment, пользовательские слушатели...). Фрагмент, управляющий AsyncTask, должен иметь возможность получить ссылку на новый экземпляр фрагмента пользовательского интерфейса после вращения.

Ответ 2

Похоже, что на мой вопрос не было ответов, но вот что я в итоге сделал:

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

Тем не менее, я считаю, что вся эта ситуация довольно запутанна (дифференциация между onSaveInstanceState(), onRetainNonConfigurationInstance() и onDestroy() и определение того, что вам нужно сохранить при каждом сценарии).