Intereting Posts
Проблема с установкой Android – Игнорирование неизвестных пакетов фильтра «платформенные инструменты» Ошибка в активности.java для телефонной разницы Какие платы разработки на основе ARM следует использовать? Как я могу изменить рингтон в андроиде программно? Как вызвать событие click на Android ListView Header? Android – блоки CheckBox ExpandableListView.OnGroupClickListener Как сбрасывать компоненты компонента пользовательского интерфейса Android и его данные, чтобы помочь решить трудновоспроизводимые ошибки ParseSdkContent failed Не удалось инициализировать класс android.graphics.Typeface Назначить статический IP-адрес для локальной сети от OTG Com.google.android.maps отсутствует? Андроид определяет, являются ли контекст активности или контекст приложения Как расширить вид из макета ящика? Как создать автоответчик для Android Попытка вызвать виртуальный метод 'android.os.Handler android.support.v4.app.FragmentHostCallback.getHandler ()' в ссылке на нулевой объект Как сделать обычное сообщение для тоста для всего экрана

Узел Android FragmentTab и фрагменты внутри фрагментов

У меня есть приложение с такой иерархией:

FragmentTabHost (Main Activity) - Fragment (tab 1 content - splitter view) - Fragment (lhs, list) - Framment (rhs, content view) - Fragment (tab 2 content) - Fragment (tab 2 content) 

Все виды фрагментов раздуваются от ресурсов.

Когда приложение запускается, все появляется и выглядит отлично. Когда я переключаюсь с первой вкладки на другую вкладку и обратно, я получаю исключения надувания, пытаясь воссоздать взгляды вкладки 1.

Копая немного глубже, это то, что происходит:

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

Я работал над этим, удалив дочерние фрагменты из диспетчера фрагментов (я использую Mono), и теперь я могу переключать вкладки без исключения.

 public override void OnDestroyView() { var ft = FragmentManager.BeginTransaction(); ft.Remove(FragmentManager.FindFragmentById(Resource.Id.ListFragment)); ft.Remove(FragmentManager.FindFragmentById(Resource.Id.ContentFragment)); ft.Commit(); base.OnDestroyView(); } 

Поэтому у меня есть несколько вопросов:

  1. Правильно ли это сделано?
  2. Если нет, как я должен это делать?
  3. В любом случае, как сохранение состояния экземпляра связывает все это, чтобы я не терял состояние отображения при переключении вкладок?

Я не уверен, как это сделать в Mono, но чтобы добавить дочерние фрагменты к другому фрагменту, вы не можете использовать FragmentManager Activity . Вместо этого вы должны использовать ChildFragmentManager хостинга Fragment :

http://developer.android.com/reference/android/app/Fragment.html#getChildFragmentManager () http://developer.android.com/reference/android/support/v4/app/Fragment.html#getChildFragmentManager ()

Основной FragmentManager Activity обрабатывает ваши вкладки.
ChildFragmentManager tab1 обрабатывает разделенные виды.

Хорошо, я, наконец, понял это:

Как было предложено выше, сначала я изменил создание фрагмента, которое будет выполняться программно, и добавили ли они в диспетчер дочерних фрагментов, например:

 public override View OnCreateView(LayoutInflater inflater, ViewGroup viewGroup, Bundle savedInstance) { var view = inflater.Inflate(Resource.Layout.MyView, viewGroup, false); // Add fragments to the child fragment manager // DONT DO THIS, SEE BELOW var tx = ChildFragmentManager.BeginTransaction(); tx.Add(Resource.Id.lhs_fragment_frame, new LhsFragment()); tx.Add(Resource.Id.rhs_fragment_frame, new RhsFragment()); tx.Commit(); return view; } 

Как и ожидалось, каждый раз, когда я переключаю вкладки, будет создан дополнительный экземпляр Lhs / RhsFragment, но я заметил, что также будет вызван старый OnCreateView Lhs / RhsFragment. Таким образом, после каждого переключения табуляции в OnCreateView будет еще один вызов. Переключение вкладок 10 раз = 11 вызовов OnCreateView. Это, очевидно, неправильно.

Посмотрев исходный код для FragmentTabHost, я вижу, что он просто отделяет и повторно прикрепляет фрагмент содержимого вкладки при переключении вкладок. Кажется, родительский Fragment's ChildFragmentManager поддерживает дочерние фрагменты и автоматически воссоздает их представления, когда родительский фрагмент снова привязан.

Итак, я переместил создание фрагментов в OnCreate и только если мы не загружаемся из сохраненного состояния:

 public override void OnCreate(Bundle savedInstanceState) { base.OnCreate(savedInstanceState); if (savedInstanceState == null) { var tx = ChildFragmentManager.BeginTransaction(); tx.Add(Resource.Id.lhs_fragment_frame, new LhsFragment()); tx.Add(Resource.Id.rhs_fragment_frame, new RhsFragment()); tx.Commit(); } } public override View OnCreateView(LayoutInflater inflater, ViewGroup viewGroup, Bundle savedInstance) { // Don't instatiate child fragments here return inflater.Inflate(Resource.Layout.MyView, viewGroup, false); } 

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

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

 public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstance) { var view = inflater.Inflate(Resource.Layout.CentresList, container, false); // ... other code ommitted ... // DONT DO THIS, SEE BELOW if (savedInstance != null) { // Restore selection _selection = savedInstance.GetString(KEY_SELECTION); } else { // Select first item _selection =_items[0]; } return view; } 

Проблема заключается в том, что хост вкладки не вызывает OnSaveInstanceState при переключении вкладок. Скорее, дочерний фрагмент остается в живых, и переменная _selection может быть просто оставлена ​​в покое.

Поэтому я переместил код для управления выбором в OnCreate:

 public override void OnCreate(Bundle savedInstance) { base.OnCreate(savedInstance); if (savedInstance != null) { // Restore Selection _selection = savedInstance.GetString(BK_SELECTION); } else { // Select first item _selection = _items[0]; } } public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstance) { // Don't restore/init _selection here return inflater.Inflate(Resource.Layout.CentresList, container, false); } 

Теперь все работает отлично, как при переключении вкладок, так и при изменении ориентации.