повторно использовать фрагменты в fragmentpageradapter


у меня есть viewpager, который просматривает фрагменты. Мой FragmentPagerAdapter подкласс создает новый фрагмент getItem метод, который кажется расточительным. Есть ли FragmentPagerAdapter эквивалентно convertView на listAdapter это позволит мне повторно использовать фрагменты, которые уже были созданы? Мой код приведен ниже.

public class ProfilePagerAdapter extends FragmentPagerAdapter {

    ArrayList<Profile> mProfiles = new ArrayList<Profile>();

    public ProfilePagerAdapter(FragmentManager fm) {
        super(fm);
    }

    /**
     * Adding a new profile object created a new page in the pager this adapter is set to.
     * @param profile
     */
    public void addProfile(Profile profile){
        mProfiles.add(profile);
    }

    @Override
    public int getCount() {
        return mProfiles.size();
    }

    @Override
    public Fragment getItem(int position) {
        return new ProfileFragment(mProfiles.get(position));
    }
}
5 66

5 ответов:

The FragmentPagerAdapter уже кэширует Fragments для вас. Каждому фрагменту присваивается тег, а затем FragmentPagerAdapter пытается вызвать findFragmentByTag. Он только вызывает getItem если результат findFragmentByTag - это null. Так что вам не придется кэшировать фрагменты самостоятельно.

приложение к сообщению Джеффа:

вы можете получить ссылку на свой Fragment in FragmentPagerAdapter используя findFragmentByTag(). Имя тега генерируется следующим образом:

private static String makeFragmentName(int viewId, int index)
{
     return "android:switcher:" + viewId + ":" + index;
}

где viewId-это идентификатор ViewPager

посмотрите на эту ссылку: http://code.google.com/p/openintents/source/browse/trunk/compatibility/AndroidSupportV2/src/android/support/v2/app/FragmentPagerAdapter.java#104

кажется, многие люди, просматривающие этот вопрос, ищут способ ссылаться на Fragments создано FragmentPagerAdapter/FragmentStatePagerAdapter. Я хотел бы предложить свое решение для этого, не полагаясь на внутри создано tags что другие ответы на здесь использовать.

в качестве бонуса этот метод также должен работать с FragmentStatePagerAdapter. См. Примечания ниже для получения более подробной информации.


проблема с текущими решениями: полагаясь на внутренний код

A многие решения, которые я видел по этому и подобным вопросам, основаны на получении ссылки на существующий Fragment по телефону FragmentManager.findFragmentByTag() и передразнивать внутренне созданный тег: "android:switcher:" + viewId + ":" + id. Проблема в том, что вы полагаетесь на внутренний исходный код, который, как мы все знаем, не гарантированно останется неизменным навсегда. Инженеры Android в Google могут легко решить изменить tag структура, которая сломает ваш код, оставив вас неспособным найдите ссылку на существующий Fragments.

альтернативное решение, не полагаясь на внутренние tag

вот простой пример, как получить ссылку на элемент Fragments возвращено FragmentPagerAdapter это не зависит от внутреннего tags установить на Fragments. Ключ должен переопределить instantiateItem() и сохранить ссылки там вместо внутри getItem().

public class SomeActivity extends Activity {
    private FragmentA m1stFragment;
    private FragmentB m2ndFragment;

    // other code in your Activity...

    private class CustomPagerAdapter extends FragmentPagerAdapter {
        // other code in your custom FragmentPagerAdapter...

        public CustomPagerAdapter(FragmentManager fm) {
            super(fm);
        }

        @Override
        public Fragment getItem(int position) {
            // Do NOT try to save references to the Fragments in getItem(),
            // because getItem() is not always called. If the Fragment
            // was already created then it will be retrieved from the FragmentManger
            // and not here (i.e. getItem() won't be called again).
            switch (position) {
                case 0:
                    return new FragmentA();
                case 1:
                    return new FragmentB();
                default:
                    // This should never happen. Always account for each position above
                    return null;
            }
        }

        // Here we can finally safely save a reference to the created
        // Fragment, no matter where it came from (either getItem() or
        // FragmentManger). Simply save the returned Fragment from
        // super.instantiateItem() into an appropriate reference depending
        // on the ViewPager position.
        @Override
        public Object instantiateItem(ViewGroup container, int position) {
            Fragment createdFragment = (Fragment) super.instantiateItem(container, position);
            // save the appropriate reference depending on position
            switch (position) {
                case 0:
                    m1stFragment = (FragmentA) createdFragment;
                    break;
                case 1:
                    m2ndFragment = (FragmentB) createdFragment;
                    break;
            }
            return createdFragment;
        }
    }

    public void someMethod() {
        // do work on the referenced Fragments, but first check if they
        // even exist yet, otherwise you'll get an NPE.

        if (m1stFragment != null) {
            // m1stFragment.doWork();
        }

        if (m2ndFragment != null) {
            // m2ndFragment.doSomeWorkToo();
        }
    }
}

или если вы предпочитаете работы с tags вместо переменных-членов класса / ссылки на Fragments вы также можете захватить tags set by FragmentPagerAdapter таким же образом: Примечание: это не относится к FragmentStatePagerAdapter так как он не поставил tags при создании Fragments.

@Override
public Object instantiateItem(ViewGroup container, int position) {
    Fragment createdFragment = (Fragment) super.instantiateItem(container, position);
    // get the tags set by FragmentPagerAdapter
    switch (position) {
        case 0:
            String firstTag = createdFragment.getTag();
            break;
        case 1:
            String secondTag = createdFragment.getTag();
            break;
    }
    // ... save the tags somewhere so you can reference them later
    return createdFragment;
}

обратите внимание, что этот метод не зависит от имитации внутреннего tag set by FragmentPagerAdapter и вместо этого использует правильные API для их извлечения. Таким образом, даже если tag изменения в будущих версиях SupportLibrary вы все равно быть безопасным.


не забудьте, что в зависимости от дизайна вашего Activity на Fragments вы пытаетесь работать на может или не может существовать, так что вы должны учитывать, что null проверяет перед использованием ссылки.

также, если вместо вы работаете с FragmentStatePagerAdapter, то вы не хотите сохранять жесткие ссылки на ваш Fragments потому что у вас может быть много из них, и жесткие ссылки будут излишне держать их в памяти. Вместо этого сохраните Fragment ссылок WeakReference переменные вместо стандартных. Вот так:

WeakReference<Fragment> m1stFragment = new WeakReference<Fragment>(createdFragment);
// ...and access them like so
Fragment firstFragment = m1stFragment.get();
if (firstFragment != null) {
    // reference hasn't been cleared yet; do work...
}

Если фрагмент остается в памяти, вы можете найти его с помощью этой функции.

public Fragment findFragmentByPosition(int position) {
    FragmentPagerAdapter fragmentPagerAdapter = getFragmentPagerAdapter();
    return getSupportFragmentManager().findFragmentByTag(
            "android:switcher:" + getViewPager().getId() + ":"
                    + fragmentPagerAdapter.getItemId(position));
}

пример кода для api поддержки v4.

Я знаю, что это (теоретически) не ответ на вопрос, а другой подход.

У меня была проблема, когда мне нужно было обновить видимые фрагменты. Что бы я ни пытался, мне это не удавалось и не удавалось с треском...

после попытки так много разных вещей, я, наконец, закончить это с помощью BroadCastReceiver. Просто отправьте трансляцию, когда вам нужно что-то сделать с видимыми фрагментами и захватить его во фрагменте.

Если вам нужен какой-то ответ ну, вы также можете отправить его через эфир.

ура