Сохранение состояния пользовательского интерфейса фрагмента после вызова отсоединения

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

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

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

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

Мой вопрос в том, является ли это допустимым подходом? Я не вижу в этом недостатков, если только нет проблем с памятью, о которых нужно беспокоиться.


person Scott Naef    schedule 15.04.2012    source источник


Ответы (1)


Это не лучший подход, и вот почему:

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

Во-вторых, это ужасное использование памяти, когда полностью раздутое корневое представление сидит без дела, когда оно не используется. Теперь записи, которые вы упомянули, не хранятся ни в каком View, а ваше представление списка имеет ссылку на созданный вами адаптер, который хранит этот адаптер в памяти вместе с вашими представлениями. Это много данных, чтобы просто сидеть без дела.

Теперь, чтобы правильно дать вам рекомендацию, вам в конечном итоге нужно провести черту между использованием памяти и производительностью, имея в виду, что, если вы планируете сделать это приложение общедоступным, существует МНОГО аппаратных устройств низкого качества.

Один из вариантов — это то, что вы уже сделали: использовать переменную savedInstanceState при отсоединении. Вы можете попробовать поместить свои 300 записей в этот Bundle и посмотреть, как это работает. Если данные представляют собой созданный вами класс, реализуйте интерфейс Parcelable (см. документацию, чтобы знать, как правильно это реализовать) и сохранить его в Bundle, а затем извлечь его позже и создать новый адаптер. Я бы настоятельно не советовал оставлять ссылки на Views между вложениями.

person Jason Robinson    schedule 15.04.2012
comment
Спасибо за ответ. Я видел, как другие предлагали скрыть фрагмент вместо вызова detach, но предположил, что это создает примерно те же накладные расходы памяти, что и мое решение. - person Scott Naef; 15.04.2012
comment
Мне нужно доработать внешний вид фактического фрагмента. Как только все стили будут завершены, я посмотрю на память, используемую представлением, и приму решение на основе этого. Существуют ли какие-либо рекомендации по допустимому использованию памяти для данного уровня API? - person Scott Naef; 15.04.2012
comment
Это будет зависеть от аппаратного обеспечения устройства, а не от версии ОС устройства. Прочтите эту статью, если вы еще не читали ее. - person Jason Robinson; 15.04.2012
comment
Следуя этому совету, я выбираю путь оптимизации для памяти, а не для отклика. В моих тестах повторное создание представления допустимо с типичным набором данных. - person Scott Naef; 02.05.2012