Android FragmentStatePagerAdapter, как пометить фрагмент, чтобы найти его позже
При использовании FragmentStatePageAdapter
я получаю фрагменты следующим образом:
@Override
public Fragment getItem(int position) {
return new SuperCoolFragment();
}
Однако позже в моем коде мне нужно найти этот фрагмент, чтобы установить свойство. В некоторых других частях приложения, где я использую фрагменты, я в основном теги их и ищу их с помощью findFragmentByTag(TAG)
, но теперь я не знаю, как это сделать.
Как можно найти фрагменты с помощью FragmentStatePageAdapter
?
Ответы
Ответ 1
* РЕДАКТИРОВАТЬ *
Как отметил @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);
}
--- EDIT:
Также добавьте это в свой адаптер, после изменения ориентации:
/**
* 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;
}
Ответ 2
Я нашел другой способ сделать это, не уверенный, будут ли какие-либо проблемы для его использования, мне кажется, что это нормально.
Я проверял код для 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)
Надеюсь, что поможет
Ответ 3
Я реализовал это, добавив функцию getItemTag(int position)
в FragmentStatePagerAdapter
. Выпадающая версия обновленного файла здесь, если кто-то еще хочет пойти по этому маршруту.
Ответ 4
Решение с сохранением фрагментов в 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);
}
}
относительно * означает, что это не так опасно, как использование рефлексии в классах классов. Классы поддержки скомпилированы в ваше приложение, и нет никакого способа, чтобы этот код работал на вашем устройстве, но сбой на каком-либо другом устройстве. Вы все же можете разбить это решение, обновив библиотеку поддержки до более новой версии
safe ** его никогда не безопасно использовать отражения; однако вы должны прибегнуть к этому методу, когда библиотека, которую вы используете, имеет недостатки дизайна.
Ответ 5
Как упоминалось в @Lancelot, вы можете просто вызвать и применить результат к вашему SuperCoolFragment:
SuperCoolFragment frag = (SuperCoolFragment) yourFragmentStatePageAdpater.instantiateItem(null, position);
Ответ 6
Я попробовал ответить Франку, что предлагает второй подход из связанного с ним учебника, бот почему-то после добавления метода getFragment() в мой ViewPagerAdapter Я не могу получить к нему доступ через mViewPager.getAdapter. getFragment(), как если бы он не существовал, поэтому я переместил объявление mPageReferenceMap из ViewPagerAdapter в класс-класс, поэтому его легко получить из любой точки охватывающего класса (в моем случае это метод обратного вызова MainActivity из другого фрагмента), что в конечном итоге делает возможно передавать данные между фрагментами.
Спасибо Фрэнку и не стесняйтесь реализовать мой прибор, если мне нравится проблема с доступом к пользовательскому методу getFragment.
Ответ 7
Другое решение - скопировать исходный код FragmentStatePagerAdapter и добавить метод getFragment
:
public Fragment getFragment(int position) {
if (position >= mFragments.size()) {
return null;
}
return mFragments.get(position);
}
Ответ 8
Переопределить setPrimaryItem
и использовать эту позицию, это будет индекс правой страницы:
@Override
public void setPrimaryItem(ViewGroup container, int position, Object object) {
super.setPrimaryItem(container,position,object);
if (position == 1) {
currentPageIndex=cameraFragment.pageIndex;
}
Ответ 9
Одиночный ответ
Это легкое решение отлично работало для меня.
фрагмент YourFragment = (YourFragment) getSupportFragmentManager(). getFragments(). get (0);
< - Если вы знаете свою позицию фрагмента в списке фрагментов
Ответ 10
Создайте держатель для хранения нового объекта SuperCoolFragment. Затем пометьте и верните объект держателя.
@Override
public Fragment getItem(int position) {
SuperCoolFragment superCoolFragment = new SuperCoolFragment();
superCoolFragment.setTag(YOUR_TAG);
return superCoolFragment;
}