У меня проблема с тем, чтобы мои фрагменты взаимодействовали друг с другом через класс Activity
, который использует FragmentPagerAdapter
, в качестве вспомогательного класса, который реализует управление вкладками и всеми деталями подключения к ViewPager
связанному TabHost
. Я реализовал то FragmentPagerAdapter
же самое, что и в образце проекта Android Support4Demos .
Главный вопрос: как получить конкретный фрагмент, FragmentManager
если у меня нет ни идентификатора, ни тега? FragmentPagerAdapter
создает фрагменты и автоматически генерирует идентификатор и теги.
android
android-fragments
fragmentpageradapter
Исмар Сломич
источник
источник
Ответы:
Краткое изложение проблемы
Примечание. В этом ответе я буду ссылаться на
FragmentPagerAdapter
его исходный код. Но общее решение также должно применяться кFragmentStatePagerAdapter
.Если вы читаете это, вы, вероятно, уже знаете, что
FragmentPagerAdapter
/FragmentStatePagerAdapter
предназначен для созданияFragments
для васViewPager
, но при воссоздании Activity (будь то вращение устройства или система, убивающая ваше приложение для восстановления памяти) ониFragments
не будут созданы снова, а вместо этого их экземпляры, извлеченные изFragmentManager
. Теперь скажите, что вамActivity
нужно получить ссылку на них,Fragments
чтобы поработать над ними. У вас нет созданныхid
илиtag
для них,Fragments
потому что ониFragmentPagerAdapter
установлены внутри . Итак, проблема в том, как получить на них ссылку без этой информации ...Проблема с текущими решениями: полагаться на внутренний код
Многие из решений , которые я видел на этом и подобных вопросах рассчитывать на получение ссылки на существующий
Fragment
по телефонуFragmentManager.findFragmentByTag()
и имитируя внутренне созданный тег:"android:switcher:" + viewId + ":" + id
. Проблема в том, что вы полагаетесь на внутренний исходный код, который, как мы все знаем, не гарантирует, что он останется неизменным навсегда. Инженеры Android в Google могут легко решить изменитьtag
структуру, которая сломает ваш код, и вы не сможете найти ссылку на существующийFragments
.Альтернативное решение, не полагаясь на внутренние
tag
Вот простой пример того, как получить ссылку на
Fragments
возвращаемый объектFragmentPagerAdapter
, который не зависит от внутреннегоtags
набора вFragments
. Ключ в том, чтобы переопределитьinstantiateItem()
и сохранить ссылки там, а не вgetItem()
.или если вы предпочитаете работать с
tags
переменными-членами класса или ссылками на них,Fragments
вы также можете получитьtags
наборFragmentPagerAdapter
таким же образом: ПРИМЕЧАНИЕ: это не относится к,FragmentStatePagerAdapter
поскольку оно не устанавливаетсяtags
при создании егоFragments
.Обратите внимание, что этот метод НЕ полагается на имитацию внутреннего
tag
набора,FragmentPagerAdapter
а вместо этого использует соответствующие API для их получения. Таким образом, даже еслиtag
изменения в будущих версияхSupportLibrary
вы все равно будете в безопасности.Не забывайте, что в зависимости от вашего дизайна
Activity
, то, надFragments
чем вы пытаетесь работать, может еще существовать, а может и не существовать, поэтому вы должны учесть это, выполнивnull
проверки перед использованием ваших ссылок.Кроме того, если вместо этого вы работаете с
FragmentStatePagerAdapter
вами, вы не хотите хранить жесткие ссылки на свои,Fragments
потому что у вас может быть их много, и жесткие ссылки излишне сохранят их в памяти. Вместо этого сохранитеFragment
ссылки вWeakReference
переменных вместо стандартных. Как это:источник
instantiateItem
. правильный способ сделать это, чтобы позвонитьinstantiateItem
вonCreate
методе вашей деятельности в окруженииstartUpdate
иfinishUpdate
. Подробности смотрите в моем ответеЯ нашел ответ на свой вопрос на основе следующего сообщения: повторное использование фрагментов в fragmentpageradapter
Я кое-что узнал:
getItem(int position)
вFragmentPagerAdapter
довольно вводящем в заблуждение названии того, что на самом деле делает этот метод. Он создает новые фрагменты, не возвращая существующие. В этом смысле метод следует переименовать во что-то вродеcreateItem(int position)
Android SDK. Таким образом, этот метод не помогает нам получать фрагменты.FragmentPagerAdapter
и, таким образом, у вас нет ссылки на фрагменты или их теги. Если у вас есть тег фрагмента, вы можете легко получить ссылку на него изFragmentManager
класса, вызвавfindFragmentByTag()
. Нам нужен способ узнать тег фрагмента в заданной позиции страницы.Решение
Добавьте следующий вспомогательный метод в свой класс, чтобы получить тег фрагмента и отправить его
findFragmentByTag()
методу.НОТА! Это тот же метод, что и
FragmentPagerAdapter
при создании новых фрагментов. См. Эту ссылку http://code.google.com/p/openintents/source/browse/trunk/compatibility/AndroidSupportV2/src/android/support/v2/app/FragmentPagerAdapter.java#104источник
onAttach()
?вам не нужно переопределять
instantiateItem
или полагаться на совместимость с внутреннимmakeFragmentName
методом, вручную создавая теги фрагментов.instantiateItem
- это общедоступный метод, поэтому вы можете и должны вызывать его вonCreate
методе своей деятельности, окруженном вызовамиstartUpdate
иfinishUpdate
методами, как описано вPagerAdapter
javadoc :Затем вы можете, используя вышеизложенное, хранить ссылки на экземпляры ваших фрагментов в локальных варах, если вам нужно. См. Пример:
instantiateItem
сначала попытается получить ссылки на существующие экземпляры фрагментов изFragmentManager
. Только если они еще не существуют, он создаст новые, используяgetItem
метод вашего адаптера, и «сохранит» ихFragmentManager
для будущего использования.Важно отметить, что даже если вам не нужно получать ссылки на ваши фрагменты, вы все равно должны вызывать
instantiateItem
все свои вкладки, окруженныеstartUpdate
/finishUpdate
в вашемonCreate
методе, например:Если вы этого не сделаете, вы рискуете, что ваши экземпляры фрагментов никогда не будут привязаны к
FragmentManager
: когда ваша активность станет переднего плана,instantiateItem
будет автоматически вызываться для получения ваших фрагментов, ноstartUpdate
/ неfinishUpdate
может (в зависимости от деталей реализации) и что они в основном сделать это начать / зафиксировать . Это может привести к тому, что ссылки на созданные экземпляры фрагментов будут потеряны очень быстро (например, при повороте экрана) и воссозданы гораздо чаще, чем необходимо. В зависимости от того, насколько «тяжелы» ваши фрагменты, это может иметь существенные последствия для производительности. Более того, в таком случае экземпляры фрагментов, хранящиеся в локальных варах, могутFragmentTransaction
становятся устаревшими: если платформа Android пытается получить их
FragmentManager
по какой-либо причине, она потерпит неудачу и, таким образом, будет создавать и использовать новые, в то время как ваши вары по-прежнему будут ссылаться на старые.источник
FragmentManager
не может просто случайно убить ( уничтожить - правильное слово) вашFragment
(подумайте, что произойдет, если он решит убитьFragment
отображаемый в данный момент;)). Обычно жизненный цикл aFragment
привязан к немуActivity
( подробности см. На github.com/xxv/android-lifecycle ) -> aFragment
может быть уничтожен, только если онActivity
был уничтожен. В таком случае , когда пользователь переходит обратно к данномуActivity
егоonCreate
будет называться снова и новый экземплярFragment
будет создан.Я сделал это так, чтобы определить Hashtable of WeakReferences следующим образом:
Затем я написал метод getItem () следующим образом:
Затем вы можете написать метод:
Кажется, это работает хорошо, и я считаю его менее хакерским, чем
трюк, поскольку он не зависит от того, как реализован FragmentPagerAdapter. Конечно, если фрагмент был освобожден FragmentPagerAdapter или если он еще не был создан, getFragment вернет null.
Если кто-то обнаружит, что в таком подходе что-то не так, комментарии приветствуются.
источник
int fragmentId
следует переименовать вint position
Я создал этот метод, который позволяет мне получить ссылку на текущий фрагмент.
источник
решение, предложенное @ personne3000, хорошее, но у него есть одна проблема: когда активность уходит в фоновый режим и убивается системой (чтобы получить некоторую свободную память), а затем восстанавливается,
fragmentReferences
будет пустым, потомуgetItem
что не будет называется.Класс ниже обрабатывает такую ситуацию:
источник
Основная проблема, связанная с получением дескриптора фрагментов, заключается в том, что вы не можете полагаться на getItem (). После изменения ориентации ссылки на фрагменты будут нулевыми, и getItem () больше не вызывается.
Вот подход, который не зависит от реализации FragmentPagerAdapter для получения тега. Переопределите instantiateItem (), который вернет фрагмент, созданный из getItem () или найденный из диспетчера фрагментов.
источник
См. Этот пост о возврате фрагментов из FragmentPagerAdapter. Полагается на то, что вы знаете индекс вашего фрагмента, но это будет установлено в getItem () (только при создании экземпляра)
источник
Мне удалось решить эту проблему, используя идентификаторы вместо тегов. (Я использую я определил FragmentStatePagerAdapter, который использует мои пользовательские фрагменты, в которых я переопределил метод onAttach, где вы где-то сохраняете идентификатор:
А затем вы просто легко получаете доступ к фрагменту внутри действия:
источник
Я не знаю, лучший ли это подход, но у меня ничего не помогло. Все остальные параметры, включая getActiveFragment, вернули значение null или вызвали сбой приложения.
Я заметил, что при повороте экрана фрагмент прикреплялся, поэтому я использовал его, чтобы отправить фрагмент обратно в действие.
Во фрагменте:
Затем в действии:
И, наконец, в действии onCreate ():
При таком подходе к действию прикрепляется фактический видимый фрагмент, не создавая новый.
источник
Не уверен, что мой метод был правильным или лучшим способом сделать это, поскольку я относительно новичок в Java / Android, но он действительно работал (я уверен, что он нарушает объектно-ориентированные принципы, но никакое другое решение не сработало для моего варианта использования).
У меня был хостинг Activity, который использовал ViewPager с FragmentStatePagerAdapter. Чтобы получить ссылки на фрагменты, созданные FragmentStatePagerAdapter, я создал интерфейс обратного вызова внутри класса фрагмента:
В процессе хостинга я реализовал интерфейс и создал LinkedHasSet для отслеживания фрагментов:
В классе ViewPagerFragment я добавил фрагменты в список внутри onAttach и удалил их внутри onDetach:
Теперь в рамках деятельности по размещению вы сможете использовать mFragments для итерации по фрагментам, которые в настоящее время существуют в FragmentStatePagerAdapter.
источник
Этот класс делает свое дело, не полагаясь на внутренние теги. Предупреждение. Доступ к фрагментам следует осуществлять с помощью метода getFragment, а не метода getItem.
источник
Просто попробуйте этот код,
источник