Принятый ответ является неоптимальным ответом. Возврат POSITION_NONE
из int getItemPosition(Object)
просто разрушает любую надежду на эффективное управление фрагментами, требуя повторного создания всех фрагментов. Он также игнорирует другую проблему. FragmentPageAdapter хранит кэшированную копию фрагмента в FragmentManager и ищет эти копии при создании экземпляра нового фрагмента. Если он находит то, что считает совпадающим фрагментом, метод public Fragment getItem(int)
не вызывается и используется кэшированная копия.
Например, предположим, что страницы 0 и 1 загружены, в FragmentManager будут кэшированные фрагменты с тегами 0 и 1. Теперь страница вставляется по индексу 0 (не забудьте вызвать notifyDataSetChanged()
), старый индекс 0 становится 1, а 1 становится 2 (об этом сигнализирует метод public int FragmentPageAdapter.getItemPosition(Object)
). Для элемента 0 было возвращено POSITION_NONE (поскольку это новая позиция), поэтому для позиции 0 вызывается метод public Object instantiateItem(ViewGroup, int)
:
public Object instantiateItem(ViewGroup container, int position) {
if (mCurTransaction == null) {
mCurTransaction = mFragmentManager.beginTransaction();
}
final long itemId = getItemId(position);
// Do we already have this fragment?
String name = makeFragmentName(container.getId(), itemId);
Fragment fragment = mFragmentManager.findFragmentByTag(name);
if (fragment != null) {
if (DEBUG) Log.v(TAG, "Attaching item #" + itemId + ": f=" + fragment);
mCurTransaction.attach(fragment);
} else {
fragment = getItem(position);
...
Посмотрите, что происходит, кэшированный фрагмент найден для позиции 0, и фрагмент, который вы хотели в позиции 1, теперь находится в позиции 0, фрагмент, который вы хотели в позиции 2, теперь находится в позиции 1, а в позиции 2 вы получаете новый фрагмент, возвращенный FragmentPageAdapter.getItem(int), который является дубликатом позиции 1.
Как это решить? Я видел много предложений по SO, в том числе:
- Всегда возвращайте POSITION_NONE из FragmentPageAdapter.getItemPosition() https://stackoverflow.com/a/7386616/2351246 - этот ответ игнорирует эффективность и управление памятью (и в конечном итоге не будет работать без очистки кэшированных фрагментов)
- Отслеживание тегов фрагментов https://stackoverflow.com/a/12104399/2351246 зависит от деталей реализации, которые могут измениться .
- И, что хуже всего, используйте магию путем обратного проектирования реализации FragmentPageAdapter https://stackoverflow.com/a/13925130/2351246, это просто ужасно.
Нет необходимости портить управление памятью или отслеживать детали внутренней реализации FragmentPagerAdapter
. Отсутствующая деталь во всех ответах заключается в том, что FragmentPagerAdapter, который хочет переупорядочить фрагменты, должен также реализовать метод public long getItemId(int position)
:
@Override
public long getItemId(int position) {
return System.identityHashCode(fragments.get(position));
}
Это обеспечивает идентификатор, не зависящий от позиции, который можно использовать для поиска правильного фрагмента в кеше FragmentManager, даже если он перемещает страницу.
person
BitByteDog
schedule
28.09.2017