Résumé du problème
Remarque: Dans cette réponse, je vais faire référence FragmentPagerAdapter
et son code source. Mais la solution générale devrait également s'appliquer à FragmentStatePagerAdapter
.
Si vous lisez ceci, vous savez probablement déjà que FragmentPagerAdapter
/ FragmentStatePagerAdapter
est censé créer Fragments
pour votre ViewPager
, mais lors de la récréation d'activité (que ce soit à partir d'une rotation de périphérique ou du système tuant votre application pour regagner la mémoire), ceux- Fragments
ci ne seront pas créés à nouveau, mais à la place instances récupérées duFragmentManager
. Dites maintenant vos Activity
besoins pour obtenir une référence à ceux-ci Fragments
pour y travailler. Vous n'avez pas créé un id
ou tag
pour ceux-ci, Fragments
car vous les FragmentPagerAdapter
définissez en interne . Le problème est donc de savoir comment obtenir une référence à eux sans cette information ...
Problème avec les solutions actuelles: s'appuyer sur le code interne
Beaucoup des solutions que je l' ai vu sur ce sujet et des questions similaires comptent sur l' obtention d' une référence à l'existant Fragment
en appelant FragmentManager.findFragmentByTag()
et en imitant l' étiquette créée en interne:"android:switcher:" + viewId + ":" + id
. Le problème avec cela est que vous vous fiez au code source interne, qui, comme nous le savons tous, n'est pas garanti de rester le même pour toujours. Les ingénieurs Android de Google pourraient facilement décider de changer la tag
structure qui briserait votre code vous laissant incapable de trouver une référence à l'existant Fragments
.
Solution alternative sans compter sur les tag
Voici un exemple simple de la façon d'obtenir une référence au Fragments
renvoyé par FragmentPagerAdapter
qui ne repose pas sur l' tags
ensemble interne du Fragments
. La clé est de remplacer instantiateItem()
et d'enregistrer les références là-dedans plutôt que dans 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();
}
}
}
ou si vous préférez travailler avec tags
au lieu de variables / références de membres de classe, Fragments
vous pouvez également récupérer l' tags
ensemble par FragmentPagerAdapter
de la même manière: REMARQUE: cela ne s'applique pas FragmentStatePagerAdapter
car il n'est pas défini tags
lors de la création de son 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;
}
Notez que cette méthode ne repose PAS sur l'imitation de l' tag
ensemble interne par FragmentPagerAdapter
et utilise à la place des API appropriées pour les récupérer. De cette façon, même si les tag
changements dans les futures versions du, SupportLibrary
vous serez toujours en sécurité.
N'oubliez pas que selon la conception de votre Activity
, le sur Fragments
lequel vous essayez de travailler peut ou peut ne pas exister encore, vous devez donc en tenir compte en effectuant des null
vérifications avant d'utiliser vos références.
De plus, si au contraire vous travaillez avec FragmentStatePagerAdapter
, vous ne voulez pas garder de références sérieuses à votre Fragments
car vous pourriez en avoir beaucoup et des références difficiles les garderaient inutilement en mémoire. Au lieu de cela, enregistrez les Fragment
références dans des WeakReference
variables au lieu de celles standard. Comme ça:
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...
}