повторно использовать фрагменты в 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 ответов:
The
FragmentPagerAdapter
уже кэшируетFragments
для вас. Каждому фрагменту присваивается тег, а затемFragmentPagerAdapter
пытается вызватьfindFragmentByTag
. Он только вызываетgetItem
если результатfindFragmentByTag
- этоnull
. Так что вам не придется кэшировать фрагменты самостоятельно.
приложение к сообщению Джеффа:
вы можете получить ссылку на свой
Fragment
inFragmentPagerAdapter
используя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 byFragmentPagerAdapter
таким же образом: Примечание: это не относится к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 byFragmentPagerAdapter
и вместо этого использует правильные 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
. Просто отправьте трансляцию, когда вам нужно что-то сделать с видимыми фрагментами и захватить его во фрагменте.Если вам нужен какой-то ответ ну, вы также можете отправить его через эфир.
ура