Android FragmentStatePagerAdapter, как пометить фрагмент, чтобы найти его позже

При использовании FragmentStatePageAdapter я получаю такие фрагменты:

  @Override public Fragment getItem(int position) { return new SuperCoolFragment(); } 

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

Как можно найти фрагменты с помощью FragmentStatePageAdapter ?

Solutions Collecting From Web of "Android FragmentStatePagerAdapter, как пометить фрагмент, чтобы найти его позже"

* РЕДАКТИРОВАТЬ *

Как отметил @ElliotM, есть лучшее решение. Не нужно ничего менять в своем адаптере, просто получите фрагмент с помощью:

 Fragment myFragment = (Fragment) adapter.instantiateItem(viewPager, viewPager.getCurrentItem()); 

* OLD SOLUTION *

Лучший вариант – это второе решение здесь: http://tamsler.blogspot.nl/2011/11/android-viewpager-and-fragments-part-ii.html

Короче: вы отслеживаете все «активные» фрагменты. В этом случае вы отслеживаете страницы фрагментов в FragmentStatePagerAdapter, который используется ViewPager.

 public Fragment getItem(int index) { Fragment myFragment = MyFragment.newInstance(); mPageReferenceMap.put(index, myFragment); return myFragment; } 

Чтобы избежать ссылки на «неактивные» фрагментные страницы, нам необходимо реализовать метод destroyItem (…) FragmentStatePagerAdapter:

 public void destroyItem(View container, int position, Object object) { super.destroyItem(container, position, object); mPageReferenceMap.remove(position); } 

… и когда вам нужно получить доступ к текущей видимой странице, вы вызываете:

 int index = mViewPager.getCurrentItem(); MyAdapter adapter = ((MyAdapter)mViewPager.getAdapter()); MyFragment fragment = adapter.getFragment(index); 

… где метод getFragment (int) MyAdapter выглядит следующим образом:

 public MyFragment getFragment(int key) { return mPageReferenceMap.get(key); } 

— РЕДАКТИРОВАТЬ:

Также добавьте это в свой адаптер, поскольку после изменения ориентации:

 /** * After an orientation change, the fragments are saved in the adapter, and * I don't want to double save them: I will retrieve them and put them in my * list again here. */ @Override public Object instantiateItem(ViewGroup container, int position) { MyFragment fragment = (MyFragment) super.instantiateItem(container, position); mPageReferenceMap.put(position, fragment); return fragment; } 

Я нашел другой способ сделать это, не уверенный, будут ли какие-либо проблемы для его использования, мне кажется, все в порядке.

Я проверял код для FragmentStatePageAdapter, и я видел этот метод:

 @Override 52 public Object More ...instantiateItem(View container, int position) { 53 // If we already have this item instantiated, there is nothing 54 // to do. This can happen when we are restoring the entire pager 55 // from its saved state, where the fragment manager has already 56 // taken care of restoring the fragments we previously had instantiated. 57 if (mFragments.size() > position) { 58 Fragment f = mFragments.get(position); 59 if (f != null) { 60 return f; 61 } 62 } 63 64 if (mCurTransaction == null) { 65 mCurTransaction = mFragmentManager.beginTransaction(); 66 } 67 68 Fragment fragment = getItem(position); 69 if (DEBUG) Log.v(TAG, "Adding item #" + position + ": f=" + fragment); 70 if (mSavedState.size() > position) { 71 Fragment.SavedState fss = mSavedState.get(position); 72 if (fss != null) { 73 fragment.setInitialSavedState(fss); 74 } 75 } 76 while (mFragments.size() <= position) { 77 mFragments.add(null); 78 } 79 fragment.setMenuVisibility(false); 80 mFragments.set(position, fragment); 81 mCurTransaction.add(container.getId(), fragment); 82 83 return fragment; 84 } 

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

 myFragmentStatePageAdpater.instantiateItem(null, 1) 

надеюсь, это поможет

Я реализовал это, добавив функцию getItemTag(int position) в FragmentStatePagerAdapter . Выпадающая версия обновленного файла находится здесь, если кто-то еще хочет пойти по этому маршруту.

Решение с сохранением фрагментов в HashMap в вашем методе getItem () не работает, если ваша деятельность воссоздана!

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

Для получения дополнительной информации см. Исходный код: FragmentStatePagerAdapter # restoreState .

Это в основном означает, что единственный способ получить ссылку на ваш фрагмент – это прибегнуть к размышлениям. Это относительно безопасно **, если вы используете библиотеку поддержки.

Вот как:

  @SuppressWarnings("unchecked") public Fragment getFragment(int position) { try { Field f = FragmentStatePagerAdapter.class.getDeclaredField("mFragments"); f.setAccessible(true); ArrayList<Fragment> fragments = (ArrayList<Fragment>) f.get(this); if (fragments.size() > position) { return fragments.get(position); } return null; } catch (Exception e) { throw new RuntimeException(e); } } 

Относительно * означает, что это не так опасно, как использование рефлексии для кластерных классов. Классы поддержки скомпилированы в ваше приложение, и нет никакого способа, чтобы этот код работал на вашем устройстве, но сбой на каком-либо другом устройстве. Вы все же можете разбить это решение, обновив библиотеку поддержки до более новой версии

Безопасный ** его никогда не безопасно использовать отражения; Однако вы должны прибегнуть к этому методу, когда библиотека, которую вы используете, имеет недостатки дизайна.

Как отметил @Lancelot, вы можете просто вызвать и привести результат к вашему SuperCoolFragment:

 SuperCoolFragment frag = (SuperCoolFragment) yourFragmentStatePageAdpater.instantiateItem(null, position); 

Я попробовал ответ Фрэнка, который предлагает второй подход из связанного с ним учебника, бот почему-то после добавления метода getFragment () в мой ViewPagerAdapter. Я не могу получить к нему доступ через mViewPager.getAdapter. GetFragment (), как если бы он не существовал, поэтому я переместил объявление mPageReferenceMap из ViewPagerAdapter в класс-класс, поэтому его легко получить из любой точки охватывающего класса (в моем случае это метод обратного вызова MainActivity из другого фрагмента), который, наконец, Позволяет передавать данные между фрагментами. Спасибо Фрэнку и не стесняйтесь реализовать мой светильник, если вам нравится, когда я сталкиваюсь с проблемой доступа к пользовательскому методу getFragment.

Другое решение – скопировать исходный код FragmentStatePagerAdapter и добавить метод getFragment :

 public Fragment getFragment(int position) { if (position >= mFragments.size()) { return null; } return mFragments.get(position); } 

Переопределите setPrimaryItem и используя эту позицию, это будет индекс правой страницы:

 @Override public void setPrimaryItem(ViewGroup container, int position, Object object) { super.setPrimaryItem(container,position,object); if (position == 1) { currentPageIndex=cameraFragment.pageIndex; } 

Одиночный ответ

Это легкое решение отлично работало для меня.

GetFragment (), getFragments (). Get (0);

<- Если вы знаете свою позицию фрагмента в списке фрагментов

Создайте держатель для хранения нового объекта SuperCoolFragment. Затем пометьте и верните объект держателя.

 @Override public Fragment getItem(int position) { SuperCoolFragment superCoolFragment = new SuperCoolFragment(); superCoolFragment.setTag(YOUR_TAG); return superCoolFragment; }