Comment obtenir des fragments lors de l'utilisation de FragmentPagerAdapter
J'ai le problème de mon fragments de communiquer les uns avec les autres par le biais de la Activity
, qui est à l'aide de la FragmentPagerAdapter
, en tant qu'assistant de la classe qui implémente la gestion des onglets et tous les détails de la connexion d'un ViewPager
avec des associés TabHost
. J'ai mis en œuvre FragmentPagerAdapter
juste que comme il est fourni par l'Android exemple de projet Support4Demos.
La question principale est de savoir comment puis-je obtenir fragment de FragmentManager
quand je n'ai pas ni l'Id ou l'Étiquette? FragmentPagerAdapter
est la création de fragments et automatique de la génération de l'Id et les Balises.
- Double Possible de l'Obtention de l'actuel Fragment d'instance dans le viewpager
- comment cela peut-il être un double d'une question qui a été posée 1 an après
- en double, comme une étiquette, pas par rapport au temps, plus tard, des questions ont plus de vues
Vous devez vous connecter pour publier un commentaire.
Résumé du problème
Remarque: Dans cette réponse, je vais de 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 destiné à créerFragments
pour votreViewPager
, mais lors de l'Activité de loisirs (que ce soit à partir d'un dispositif de rotation ou la destruction de votre Application pour retrouver la mémoire) cesFragments
ne sera pas créé de nouveau, mais au lieu de leur des instances extraites de laFragmentManager
. Maintenant dire que votreActivity
besoins pour obtenir une référence à cesFragments
de faire un travail sur eux. Vous n'avez pas deid
outag
pour ces crééFragments
parce queFragmentPagerAdapter
définir en interne. Donc, le problème est de savoir comment obtenir une référence à eux sans que l'information...Problème avec les solutions actuelles: en s'appuyant sur le code interne
Beaucoup de solutions que j'ai vu sur ce type de questions s'appuient sur l'obtention d'une référence à la
Fragment
en appelantFragmentManager.findFragmentByTag()
et imitant le créées en interne balise:"android:switcher:" + viewId + ":" + id
. Le problème, c'est que vous êtes en s'appuyant sur l'intérieur du code source, qui comme nous le savons tous n'est pas assuré de rester le même pour toujours. Le Android ingénieurs de chez Google pourrait bien décider de changer letag
structure qui permettrait de casser votre code, vous laissant incapable de trouver une référence à laFragments
.Solution alternative sans compter sur interne
tag
Voici un exemple simple de comment obtenir une référence à l'
Fragments
retourné parFragmentPagerAdapter
qui ne repose pas sur l'internetags
ensemble sur leFragments
. La clé est de remplacerinstantiateItem()
et enregistrer les références y au lieu degetItem()
.ou si vous préférez travailler avec des
tags
à la place de membre de la classe des variables/les références à laFragments
vous pouvez également saisir letags
fixé parFragmentPagerAdapter
de la même manière:REMARQUE: ceci ne s'applique pas à
FragmentStatePagerAdapter
car il ne définit pastags
lors de la création de sonFragments
.Noter que cette méthode ne repose PAS sur imitant l'intérieur
tag
fixé parFragmentPagerAdapter
et utilise à la place la bonne Api pour les récupérer. De cette manière, même si letag
changements dans les futures versions de laSupportLibrary
vous serez toujours en sécurité.N'oubliez pas que, selon la conception de votre
Activity
, leFragments
vous essayez de travailler sur peut ou peut ne pas exister encore, de sorte que vous devez tenir compte de cela en faisantnull
vérifications avant d'utiliser vos références.Aussi, si, au lieu vous travaillez avec
FragmentStatePagerAdapter
, alors vous ne voulez pas garder dur références à votreFragments
parce que vous pourriez avoir beaucoup d'entre eux et dur références inutilement les garder en mémoire. Au lieu d'enregistrer leFragment
références dansWeakReference
des variables au lieu de standard. Comme ceci:instantiateItem
. la bonne façon de le faire est de appelinstantiateItem
dansonCreate
méthode de votre activité entouré parstartUpdate
etfinishUpdate
. Voir ma réponse pour plus de détailsJ'ai trouvé réponse à ma question en se basant sur le post suivant: la réutilisation de fragments dans un fragmentpageradapter
Quelques choses que j'ai apprises:
getItem(int position)
dans leFragmentPagerAdapter
est plutôt trompeur nom de ce que cette méthode ne fait. Il crée de nouveaux fragments, de ne pas retourner existants. Dans ce sens, la méthode devrait être renommé quelque chose commecreateItem(int position)
dans le SDK Android. Si cette méthode ne permet pas d'obtenir des fragments.FragmentPagerAdapter
et donc ce qui signifie que vous n'avez aucune référence à l'Fragments ou de leurs tags. Si vous avez fragment de la balise, vous pouvez facilement récupérer de référence à partir de laFragmentManager
en appelantfindFragmentByTag()
. Nous avons besoin d'un moyen de trouver la balise d'un fragment à la page donnée de position.Solution
Ajouter la suite de la méthode d'assistance dans votre classe pour récupérer le fragment de la balise et de l'envoyer à la
findFragmentByTag()
méthode.REMARQUE! C'est une méthode identique que
FragmentPagerAdapter
utiliser lors de la création de nouveaux fragments. Voir ce lien http://code.google.com/p/openintents/source/browse/trunk/compatibility/AndroidSupportV2/src/android/support/v2/app/FragmentPagerAdapter.java#104onAttach()
?instantiateItem
dansonCreate
méthode de votre activité entouré parstartUpdate
etfinishUpdate
pour obtenir des références pour vos fragments (les fragments sont mis en cache dans FragmentManager, donc pas besoin de s'inquiéter que vous pouvez créer des instances inutiles). Voir ma réponse pour plus de détails.Le chemin que j'ai fait c'est de définir une table de hachage de WeakReferences comme suit:
Ensuite, j'ai écrit la méthode getItem() comme ceci:
Ensuite, vous pouvez écrire une méthode:
Cela semble bien fonctionner et je le trouve un peu moins hacky que le
ruse, car il ne repose pas sur la façon dont le FragmentPagerAdapter est mis en œuvre.
Bien sûr, si le fragment a été publié par le FragmentPagerAdapter ou si elle n'a pas encore été créé, getFragment retournera null.
Si quelqu'un trouve quelque chose de mal avec cette approche, les commentaires sont plus que bienvenus.
int fragmentId
devrait être renomméint position
vous n'avez pas besoin de remplacer
instantiateItem
ni compter sur la compatibilité de la création fragment de balises internesmakeFragmentName
méthode.instantiateItem
est un public méthode de sorte que vous pouvez (et en fait, vous devrait) enonCreate
méthode de votre activité d'obtenir des références à des instances de vos fragments et de les stocker sur local vars si vous avez besoin d'. N'oubliez pas de les entourer d'un ensemble deinstantiateItem
appels avecstartUpdate
etfinishUpdate
méthodes décrites dansPagerAdapter
javadoc:Ainsi, par exemple, c'est la façon de stocker les références de votre onglet fragments dans
onCreate
méthode:instantiateItem
va d'abord essayer d'obtenir des références existantes fragment d'instances deFragmentManager
. Seulement si ils n'existent pas encore, il permettra de créer de nouveaux à l'aidegetItem
méthode de votre adaptateur et "store" dans leFragmentManager
pour toute utilisation future.Quelques informations supplémentaires:
Si vous n'appelez pas
instantiateItem
entouré parstartUpdate
/finishUpdate
dans votreonCreate
méthode, puis, vous risquez que votre fragment instances ne sera jamais commis àFragmentManager
: quand votre activité devient premier planinstantiateItem
sera appelé automatiquement pour obtenir votre des fragments, maisstartUpdate
/finishUpdate
peut pas (selon les détails de mise en œuvre) et ce que n'est begin/commit unFragmentTransaction
.Cette peut résultat dans les références à la création de fragment d'instances de perdre très rapidement (par exemple lorsque vous faites pivoter votre écran) et recréé beaucoup plus souvent que nécessaire. Selon la façon dont "lourd" vos fragments sont, il peut avoir une partie non négligeable de la performance conséquences.
Plus important encore, cependant, dans de tels cas, les instances de fragments stockés sur local vars va devenir obsolète: depuis la plate-forme android n'a pas été en mesure d'obtenir le même cas de
FragmentManager
il peut créer et d'utiliser de nouvelles, tandis que votre vars va encore faire référence à l'ancien.Fragment
(pensez à ce qui arriverait si elle a décidé de tuer unFragment
qui est actuellement à l'affiche 😉 ). Généralement, le cycle de vie d'unFragment
est lié à sonActivity
(voir github.com/xxv/android-lifecycle pour plus de détails) -> unFragment
ne peut être détruite si saActivity
a été détruit. Dans de tels cas, lorsque l'utilisateur revient à la donnéeActivity
sononCreate
sera appelée de nouveau et une nouvelle instance de laFragment
sera créé.J'ai créé cette méthode qui fonctionne pour moi d'obtenir une référence à l'actuel fragment.
la solution proposée par @personne3000 est agréable, mais il a un problème: lorsque l'activité se passe à l'arrière-plan et se fait tuer par le système (afin d'obtenir une certaine quantité de mémoire disponible), puis restauré, le
fragmentReferences
sera vide, parce quegetItem
ne serait pas appelé.La classe ci-dessous gère la situation:
La route principale bloc avec l'obtention d'une poignée pour les fragments, c'est que vous ne pouvez pas compter sur getItem(). Après un changement d'orientation, les références à les fragments seront nulles et getItem() n'est pas appelé à nouveau.
Ici est une approche qui ne s'appuie pas sur la mise en œuvre de FragmentPagerAdapter pour obtenir la balise. Remplacer instantiateItem() qui renvoie le fragment créé à partir de getItem() ou trouvés à partir du fragment manager.
J'ai toujours l'utilisation de cette classe de base, quand j'ai besoin de l'accès de l'enfant fragments ou primaire (actuellement visible) fragment. Il ne repose pas sur des détails de mise en œuvre et il prend soin de changements de cycle de vie, parce que remplacé les méthodes appelées dans les deux cas - lorsqu'un nouveau fragment de l'instance créée et quand instance obtient reçu de FragmentManager.
getFragments()
retourne la liste de toutes les valeurs null.J'ai réussi à résoudre ce problème en utilisant l'id de la place de balises. (Je l'utilise j'ai défini FragmentStatePagerAdapter qui utilise mon custom Fragments dans laquelle j'ai remplacé le onAttach méthode, où vous enregistrez l'id quelque part:
Et puis vous venez d'accéder au fragment facilement à l'intérieur de l'activité:
Voir ce post sur le retour des fragments de la FragmentPagerAdapter. Il compte sur vous, sachant que l'index de votre fragment - mais ce serait fixé getItem() (à l'instanciation seulement)
Je ne sais pas si c'est la meilleure approche, mais rien d'autre n'a fonctionné pour moi.
Toutes les autres options, y compris getActiveFragment retourné null ou causés à l'application de crash.
J'ai remarqué que sur la rotation de l'écran le fragment a été rattaché je l'ai donc utilisé pour envoyer le fragment de retour à l'activité.
Dans le fragment:
Puis dans l'activité:
Et enfin dans l'activité onCreate():
Cette approche joint le visible fragment à l'activité sans en créer une nouvelle.
Ne sais pas si ma méthode est la bonne ou la meilleure façon de le faire depuis que je suis un parent débutant avec Java/Android, mais il a fait un travail (je suis sûr qu'il viole orientée objet principes, mais aucune autre solution a fonctionné pour mon cas d'utilisation).
J'ai eu une Activité d'hébergement qui a été à l'aide d'un ViewPager avec un FragmentStatePagerAdapter. Afin d'obtenir des références pour les Fragments qui ont été créés par FragmentStatePagerAdapter j'ai créé une interface de rappel dans le fragment de classe:
Dans l'activité d'hébergement que j'ai implémenté l'interface et créé un LinkedHasSet de garder une trace des fragments:
Dans le ViewPagerFragment classe, j'ai ajouté les fragments de la liste dans les onAttach et les ont enlevés dans onDetach:
Au sein de l'activité d'hébergement vous allez maintenant être en mesure d'utiliser mFragments pour itérer sur les fragments qui existent actuellement dans la FragmentStatePagerAdapter.
Cette classe l'affaire sans compter sur les balises internes. Avertissement: les Fragments doivent être accessibles à l'aide de la getFragment méthode et non pas le getItem un.
Il suffit d'aller essayer ce code,