Je travaille avec un FragmentStatePagerAdapter en utilisant cet exemple .
La classe MyAdapter est implémentée comme suit:
public static class MyAdapter extends FragmentStatePagerAdapter {
public MyAdapter(FragmentManager fm) {
super(fm);
}
@Override
public int getCount() {
return NUM_ITEMS;
}
@Override
public Fragment getItem(int position) {
return ArrayListFragment.newInstance(position);
}
}
La classe ListFragment inclut la méthode suivante pour créer une nouvelle instance:
/**
* Create a new instance of CountingFragment, providing "num"
* as an argument.
*/
static ArrayListFragment newInstance(int num) {
ArrayListFragment f = new ArrayListFragment();
// Supply num input as an argument.
Bundle args = new Bundle();
args.putInt("num", num);
f.setArguments(args);
return f;
}
Lorsque je crée un nouvel adaptateur de paginisateur d'état de fragment dans mon activité, getItem
est appelé, qui à son tour appelle la méthode newInstance
de la classe ListFragment. C’est génial quand je veux créer un nouveau fragment.
Mais il m'est difficile de savoir comment modifier getItem
(si nécessaire) pour obtenir l'objet fragment lorsqu'il existe déjà et les pages utilisateur, par exemple, de la page 2 à la page 1. J'aimerais que mon activité soit récupérer ce fragment existant précédemment créé afin qu'il puisse exécuter une classe interne AsyncMethod
, qui réside dans la classe fragment.
J'ai mis en place quelque chose de similaire à ce que vous avez. J'ai étendu la classe FragmentPagerAdapter
comme ceci:
public class ContactsFragmentPagerAdapter extends FragmentPagerAdapter {
ActionBar mActionBar;
private List<Fragment> mFragments;
public ContactsFragmentPagerAdapter(FragmentManager fm, List<Fragment> fragments) {
super(fm);
mFragments = fragments;
}
@Override
public int getCount() {
return mFragments.size();
}
@Override
public Fragment getItem(int position) {
return mFragments.get(position);
}
public void setActionBar(ActionBar bar) {
mActionBar = bar;
}
}
Notez que j'ai ajouté un argument au constructeur pour lui transmettre les objets List
of Fragment
. De cette façon, la méthode getItem()
de cette classe peut renvoyer toute classe qui étend Fragment
ou l’une de ses sous-classes et non une classe ArrayListFragment
spécifique comme vous l’avez fait.
Dans la Activity
où j'instancie ma sous-classe de FragmentPagerAdapter
, j'ai passé dans la liste des objets Fragment
:
Classe l'instanciation de FragmentPagerAdapter
public final class ContactManager extends Activity {
private ContactsFragmentPagerAdapter mAdapter;
private ViewPager mPager;
public ActionBar mActionBar;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.contact_manager);
List<Fragment> fragments = new Vector<Fragment>();
fragments.add(Fragment.instantiate(this, ContactsListFragment.class.getName()));
fragments.add(Fragment.instantiate(this, GroupsListFragment.class.getName()));
mAdapter = new ContactsFragmentPagerAdapter(this.getFragmentManager(), fragments);
mPager = (ViewPager) findViewById(R.id.pager);
mPager.setAdapter(mAdapter);
mPager.setOnPageChangeListener(new OnPageChangeListener() {
@Override
public void onPageScrollStateChanged(int arg0) {}
@Override
public void onPageScrolled(int arg0, float arg1, int arg2) {}
@Override
public void onPageSelected(int arg0) {
mActionBar.getTabAt(arg0).select();
}
});
}
}
En accédant à la variable "fragments", vous pouvez accéder à une Fragment
créée précédemment afin de pouvoir exécuter des méthodes de cette Fragment
.
Je pense que la solution est beaucoup plus simple que les réponses fournies.
Si vous consultez la source de FragmentStatePagerAdapter.instantiateItem()
, vous remarquerez que instantiateItem()
gère cette logique pour vous et que votre implémentation de getItem()
devrait toujours renvoyer une nouvelle instance.
Donc, pour renvoyer un fragment existant, faites simplement (en supposant que vous appelez de ViewPager
):
Fragment f = (Fragment) getAdapter().instantiateItem(this, getCurrentItem());
Bien que la solution de @ imiric soit très concise, cela me dérange toujours de savoir qu'elle nécessite une connaissance de la mise en œuvre de la classe. Ma solution consiste à ajouter les éléments suivants à votre adaptateur, ce qui devrait se comporter correctement avec un FragmentStatePagerAdapter en détruisant éventuellement des fragments:
private SparseArray<WeakReference<Fragment>> mFragments = new SparseArray<>();
@Override
public Object instantiateItem(ViewGroup container, int position) {
Fragment f = (Fragment) super.instantiateItem(container, position);
mFragments.put(position, new WeakReference<>(f)); // Remember what fragment was in position
return f;
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
super.destroyItem(container, position, object);
mFragments.remove(position);
}
public Fragment getFragment(int position) {
WeakReference<Fragment> ref = mFragments.get(position);
Fragment f = ref != null ? ref.get() : null;
if (f == null) {
Log.d(TAG, "fragment for " + position + " is null!");
}
return f;
}
public class MyPagerAdapter extends FragmentStatePagerAdapter {
final Context m_context;
final WeakReference<Fragment>[] m_fragments;
public DetailPagerAdapter(FragmentManager fm) {
super(fm);
m_context = ...
m_fragments = new WeakReference[enter size here];
}
@Override
public Fragment getItem(int position) {
final Fragment fragment = instantiate your fragment;
m_fragments[position] = new WeakReference<Fragment>(fragment);
return fragment;
}
@Override
public int getCount() {
return ...
}
public Fragment getFragment(final int position) {
return m_fragments[position] == null ? null :
m_fragments[position].get();
}
}
Vous n'avez pas besoin de modifier FragmentPagerAdapter, car les fragments sont mis en cache par FragmentManager. Donc, vous devez avoir besoin de trouver à l'intérieur. Utilisez cette fonction pour rechercher le fragment par position d’adaptateur de pageur.
public Fragment findFragmentByPosition(int position) {
FragmentPagerAdapter fragmentPagerAdapter = getFragmentPagerAdapter();
return getSupportFragmentManager().findFragmentByTag(
"Android:switcher:" + getViewPager().getId() + ":"
+ fragmentPagerAdapter.getItemId(position));
}
Exemple de code pour l'API de support v4.