J'ai du mal à faire en sorte que mes fragments communiquent entre eux via le Activity
, qui utilise le FragmentPagerAdapter
, comme classe d'assistance qui implémente la gestion des onglets et tous les détails de connexion d'un ViewPager
avec associé TabHost
. J'ai implémenté FragmentPagerAdapter
exactement la même chose que celle fournie par l'exemple de projet Android Support4Demos .
La question principale est de savoir comment puis-je obtenir un fragment particulier à partir FragmentManager
duquel je n'ai ni identifiant ni tag? FragmentPagerAdapter
crée les fragments et génère automatiquement l'ID et les balises.
android
android-fragments
fragmentpageradapter
Ismar Slomic
la source
la source
Réponses:
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éerFragments
pour votreViewPager
, 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 vosActivity
besoins pour obtenir une référence à ceux-ciFragments
pour y travailler. Vous n'avez pas créé unid
outag
pour ceux-ci,Fragments
car vous lesFragmentPagerAdapter
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 appelantFragmentManager.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 latag
structure qui briserait votre code vous laissant incapable de trouver une référence à l'existantFragments
.Solution alternative sans compter sur les
tag
Voici un exemple simple de la façon d'obtenir une référence au
Fragments
renvoyé parFragmentPagerAdapter
qui ne repose pas sur l'tags
ensemble interne duFragments
. La clé est de remplacerinstantiateItem()
et d'enregistrer les références là-dedans plutôt que dansgetItem()
.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 parFragmentPagerAdapter
de la même manière: REMARQUE: cela ne s'applique pasFragmentStatePagerAdapter
car il n'est pas définitags
lors de la création de sonFragments
.Notez que cette méthode ne repose PAS sur l'imitation de l'
tag
ensemble interne parFragmentPagerAdapter
et utilise à la place des API appropriées pour les récupérer. De cette façon, même si lestag
changements dans les futures versions du,SupportLibrary
vous serez toujours en sécurité.N'oubliez pas que selon la conception de votre
Activity
, le surFragments
lequel vous essayez de travailler peut ou peut ne pas exister encore, vous devez donc en tenir compte en effectuant desnull
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 à votreFragments
car vous pourriez en avoir beaucoup et des références difficiles les garderaient inutilement en mémoire. Au lieu de cela, enregistrez lesFragment
références dans desWeakReference
variables au lieu de celles standard. Comme ça:la source
instantiateItem
. la bonne façon de le faire est d' appelerinstantiateItem
à laonCreate
méthode de votre activité entouréestartUpdate
etfinishUpdate
. Voir ma réponse pour plus de détailsJ'ai trouvé une réponse à ma question sur la base du post suivant: réutilisation de fragments dans un fragmentpageradapter
Peu de choses que j'ai apprises:
getItem(int position)
dans leFragmentPagerAdapter
nom plutôt trompeur de ce que cette méthode fait réellement. Il crée de nouveaux fragments, sans renvoyer ceux existants. Dans ce sens, la méthode doit être renommée en quelque chose commecreateItem(int position)
dans le SDK Android. Donc, cette méthode ne nous aide pas à obtenir des fragments.FragmentPagerAdapter
et, ce qui signifie que vous n'avez aucune référence aux fragments ou à leurs balises. Si vous avez une balise fragment, vous pouvez facilement en récupérer une référence à partir deFragmentManager
en appelantfindFragmentByTag()
. Nous avons besoin d'un moyen de trouver la balise d'un fragment à une position de page donnée.Solution
Ajoutez la méthode d'assistance suivante dans votre classe pour récupérer la balise de fragment et l'envoyer à la
findFragmentByTag()
méthode.REMARQUE! Il s'agit d'une méthode identique à celle
FragmentPagerAdapter
utilisée 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#104la source
onAttach()
?vous n'avez pas besoin de remplacer
instantiateItem
ni de vous fier à la compatibilité avec lamakeFragmentName
méthode interne en créant manuellement des balises de fragment.instantiateItem
est une publique méthode afin que vous puissiez et réellement devrait l' appeler dans laonCreate
méthode de votre activité entourée d'appels àstartUpdate
etfinishUpdate
procédés décrits dansPagerAdapter
javadoc :Vous pouvez ensuite, par le biais de ce qui précède, stocker des références aux instances de vos fragments sur des variables locales si vous en avez besoin. Voir exemple:
instantiateItem
essaiera d'abord d'obtenir des références à des instances de fragment existantes à partir deFragmentManager
. Seulement s'ils n'existent pas encore, il en créera de nouveaux en utilisant lagetItem
méthode de votre adaptateur et les «stockera» dans leFragmentManager
pour toute utilisation future.Il est important de noter que même si vous n'avez pas besoin d'obtenir des références à vos fragments, vous devez quand même appeler
instantiateItem
tous vos onglets entourés parstartUpdate
/finishUpdate
dans votreonCreate
méthode comme ceci:Si vous ne le faites pas, vous risquez que vos instances de fragments ne seront jamais engagés à
FragmentManager
: lorsque votre activité devient de premier planinstantiateItem
sera automatiquement appelée pour obtenir vos fragments, maisstartUpdate
/finishUpdate
peuvent pas (selon les détails de mise en œuvre) et ce qu'ils essentiellement faire est de commencer / valider unFragmentTransaction
.Cela peut entraîner la perte très rapide des références aux instances de fragment créées (par exemple lorsque vous faites pivoter votre écran) et la recréation beaucoup plus souvent que nécessaire. En fonction de la «lourdeur» de vos fragments, cela peut avoir des conséquences non négligeables sur les performances.
De plus, dans ce cas, des instances de fragments stockés sur des variables locales peuventdeviennent obsolètes: si la plate-forme Android tente de les obtenir
FragmentManager
pour une raison quelconque, elle échouera et en créera et en utilisera de nouvelles, tandis que vos vars référenceront toujours les anciens.la source
FragmentManager
ne peut pas simplement tuer au hasard ( détruire est le mot juste ici) votreFragment
(pensez à ce qui se passerait s'il décidait de tuer unFragment
qui est actuellement affiché;)). En général, le cycle de vie d'unFragment
est lié à sonActivity
(voir github.com/xxv/android-lifecycle pour plus de détails) -> aFragment
ne peut être détruit que s'il aActivity
été détruit. Dans ce cas, lorsqu'un utilisateur retourne à la donnée,Activity
elleonCreate
sera appelée à nouveau et une nouvelle instance de laFragment
sera créée.La façon dont je l'ai fait 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 piraté que le
astuce, car il ne dépend pas de la façon dont le FragmentPagerAdapter est implémenté. Bien sûr, si le fragment a été publié par le FragmentPagerAdapter ou s'il n'a pas encore été créé, getFragment renverra null.
Si quelqu'un trouve quelque chose qui ne va pas avec cette approche, les commentaires sont plus que bienvenus.
la source
int fragmentId
devrait être renommé enint position
J'ai créé cette méthode qui fonctionne pour moi pour obtenir une référence au fragment actuel.
la source
la solution suggérée par @ personne3000 est sympa, mais elle a un problème: quand l'activité passe en arrière-plan et est tuée par le système (afin d'avoir de la mémoire libre) puis restaurée, le
fragmentReferences
sera vide, cargetItem
ne serait pas appelé.La classe ci-dessous gère une telle situation:
la source
Le principal obstacle à l'obtention d'une poignée sur les fragments est que vous ne pouvez pas compter sur getItem (). Après un changement d'orientation, les références aux fragments seront nulles et getItem () n'est plus appelée.
Voici une approche qui ne repose pas sur l'implémentation de FragmentPagerAdapter pour obtenir la balise. Remplacez instantiateItem () qui renverra le fragment créé à partir de getItem () ou trouvé à partir du gestionnaire de fragments.
la source
Voir cet article sur le retour de fragments de FragmentPagerAdapter. Cela dépend de votre connaissance de l'index de votre fragment - mais cela serait défini dans getItem () (à l'instanciation uniquement)
la source
J'ai réussi à résoudre ce problème en utilisant des identifiants au lieu de balises. (J'utilise J'ai défini FragmentStatePagerAdapter qui utilise mes Fragments personnalisés dans lesquels j'ai remplacé la méthode onAttach, où vous enregistrez l'id quelque part:
Et puis vous accédez simplement au fragment facilement à l'intérieur de l'activité:
la source
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, ont renvoyé null ou ont provoqué le blocage de l'application.
J'ai remarqué que lors de la rotation de l'écran, le fragment était attaché, je l'ai donc utilisé pour renvoyer le fragment à l'activité.
Dans le fragment:
Puis dans l'activité:
Et enfin dans l'activité onCreate ():
Cette approche associe le fragment visible réel à l'activité sans en créer un nouveau.
la source
Je ne sais pas si ma méthode était la bonne ou la meilleure façon de le faire puisque je suis un débutant relatif avec Java / Android, mais cela a fonctionné (je suis sûr que cela viole les principes orientés objet mais aucune autre solution n'a fonctionné pour mon cas d'utilisation).
J'avais une activité d'hébergement qui utilisait un ViewPager avec un FragmentStatePagerAdapter. Afin d'obtenir des références aux fragments qui ont été créés par FragmentStatePagerAdapter, j'ai créé une interface de rappel dans la classe de fragment:
Dans l'activité d'hébergement, j'ai implémenté l'interface et créé un LinkedHasSet pour garder une trace des fragments:
Dans la classe ViewPagerFragment, j'ai ajouté les fragments à la liste dans onAttach et je les ai supprimés dans onDetach:
Dans le cadre de l'activité d'hébergement, vous pourrez désormais utiliser mFragments pour parcourir les fragments qui existent actuellement dans FragmentStatePagerAdapter.
la source
Cette classe fait l'affaire sans s'appuyer sur des balises internes. Attention: les fragments doivent être accédés à l'aide de la méthode getFragment et non de celle getItem.
la source
Continuez d'essayer ce code,
la source