Для получения фрагментов из ViewPager есть много ответов здесь и в других связанных с этим темах / блогах.Все, кого я видел, сломаны, и обычно они попадают в один из двух типов, перечисленных ниже.Существуют и другие допустимые решения, если вы хотите получить только текущий фрагмент, например этот другой ответ в этой теме.
При использовании FragmentPagerAdapter
увидеть ниже.При использовании FragmentStatePagerAdapter
стоит посмотреть на это .Захват индексов, которые не являются текущими в FragmentStateAdapter, не так полезен, так как по своей природе они будут полностью снесены, вырваны из поля зрения вне рамок ScreenLimit.
THEUNHAPPY PATHS
Неверно: ведите свой собственный внутренний список фрагментов, добавляемый, когда FragmentPagerAdapter.getItem()
вызывается
- Обычно используется
SparseArray
или Map
- Не один из многих примеров, которые я видел, описывает события жизненного цикла, поэтому это решение хрупкое.Поскольку
getItem
вызывается только в первый раз, когда страница прокручивается (или получается, если ваш ViewPager.setOffscreenPageLimit(x)
> 0) в ViewPager
, если хост Activity
/ Fragment
убит или перезапущен, тогда внутренний SpaseArray
будет уничтожено при воссоздании пользовательской FragmentPagerActivity, но за кулисами внутренние фрагменты ViewPager будут воссозданы, и getItem
будет NOT вызываться для любого из индексов, поэтому возможность получитьфрагмент из индекса будет потерян навсегда.Вы можете объяснить это, сохранив и восстановив эти фрагменты ссылок через FragmentManager.getFragment()
и putFragment
, но это начинает становиться грязным ИМХО.
Неправильно: Создайте свой собственный идентификатор тега, соответствующийиспользуется под капотом в FragmentPagerAdapter
и используется для извлечения фрагментов страницы из FragmentManager
- Это лучше, поскольку оно справляется с проблемой потерянных фрагментов впервое решение с внутренним массивом, но, как справедливо указано в ответах выше и в других местах сети - оно выглядит хакерским, как его приватный метод, внутренний по отношению к
ViewPager
, который может измениться в любое время или для любогоВерсия ОС.
Метод, воссозданный для этого решения:
private static String makeFragmentName(int viewId, long id) {
return "android:switcher:" + viewId + ":" + id;
}
СЧАСТЛИВЫЙ ПУТЬ: ViewPager.instantiateItem()
Подход, аналогичный getItem()
выше, но не нарушающий жизненный цикл , заключается в том, чтобы подключаться к instantiateItem()
вместо getItem()
, так как первый будет вызываться при каждом создании / доступе к индексу.См. этот ответ
СЧАСТЛИВЫЙ ПУТЬ: Создайте свой собственный FragmentViewPager
Создайте свой собственный FragmentViewPager
класс из источника последней поддержки lib и измените метод, используемый внутри для генерации тегов фрагмента.Вы можете заменить его ниже.Преимущество этого в том, что вы знаете, что создание тега никогда не изменится, и вы не будете полагаться на закрытый API / метод, который всегда опасен.
/**
* @param containerViewId the ViewPager this adapter is being supplied to
* @param id pass in getItemId(position) as this is whats used internally in this class
* @return the tag used for this pages fragment
*/
public static String makeFragmentName(int containerViewId, long id) {
return "android:switcher:" + containerViewId + ":" + id;
}
Тогда, как говорит док, когда вы хотите получитьфрагмент, используемый для индекса, просто вызывает что-то вроде этого метода (который вы можете поместить в пользовательский FragmentPagerAdapter
или подкласс), зная, что результат может быть нулевым , если getItem еще не был вызван для этой страницы, т.е.оно еще не было создано.
/**
* @return may return null if the fragment has not been instantiated yet for that position - this depends on if the fragment has been viewed
* yet OR is a sibling covered by {@link android.support.v4.view.ViewPager#setOffscreenPageLimit(int)}. Can use this to call methods on
* the current positions fragment.
*/
public @Nullable Fragment getFragmentForPosition(int position)
{
String tag = makeFragmentName(mViewPager.getId(), getItemId(position));
Fragment fragment = getSupportFragmentManager().findFragmentByTag(tag);
return fragment;
}
Это простое решение, которое решает проблемы в двух других решениях, которые можно найти в Интернете