Подтвердить что ты не робот

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

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

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

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

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

4b9b3361

Ответ 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;
}