J'utilise la compatibilité v4 ViewPager sous Android. Mon FragmentActivity a un tas de données qui doivent être affichées de différentes manières sur différentes pages de mon ViewPager. Jusqu'à présent, je n'ai que 3 instances du même ListFragment, mais à l'avenir j'aurai 3 instances de ListFragments différents. Le ViewPager est sur un écran de téléphone vertical, les listes ne sont pas côte à côte.
Maintenant, un bouton sur le ListFragment démarre une activité pleine page distincte (via FragmentActivity), qui retourne et FragmentActivity modifie les données, les enregistre, puis tente de mettre à jour toutes les vues dans son ViewPager. C'est ici, où je suis coincé.
public class ProgressMainActivity extends FragmentActivity
{
MyAdapter mAdapter;
ViewPager mPager;
@Override
public void onCreate(Bundle savedInstanceState)
{
...
mAdapter = new MyAdapter(getSupportFragmentManager());
mPager = (ViewPager) findViewById(R.id.viewpager);
mPager.setAdapter(mAdapter);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data)
{
...
updateFragments();
...
}
public void updateFragments()
{
//Attempt 1:
//mAdapter.notifyDataSetChanged();
//mPager.setAdapter(mAdapter);
//Attempt 2:
//HomeListFragment fragment = (HomeListFragment) getSupportFragmentManager().findFragmentById(mAdapter.fragId[0]);
//fragment.updateDisplay();
}
public static class MyAdapter extends FragmentPagerAdapter implements
TitleProvider
{
int[] fragId = {0,0,0,0,0};
public MyAdapter(FragmentManager fm)
{
super(fm);
}
@Override
public String getTitle(int position){
return titles[position];
}
@Override
public int getCount(){
return titles.length;
}
@Override
public Fragment getItem(int position)
{
Fragment frag = HomeListFragment.newInstance(position);
//Attempt 2:
//fragId[position] = frag.getId();
return frag;
}
@Override
public int getItemPosition(Object object) {
return POSITION_NONE; //To make notifyDataSetChanged() do something
}
}
public class HomeListFragment extends ListFragment
{
...
public static HomeListFragment newInstance(int num)
{
HomeListFragment f = new HomeListFragment();
...
return f;
}
...
Maintenant, comme vous pouvez le voir, ma première tentative a été de notifierDataSetChanged sur l'ensemble du FragmentPagerAdapter, et cela a montré qu'il fallait parfois mettre à jour les données, mais d'autres j'ai eu une IllegalStateException: impossible d'effectuer cette action après onSaveInstanceState.
Ma deuxième tentative consistait à essayer d'appeler une fonction de mise à jour dans mon ListFragment, mais getId dans getItem a renvoyé 0. Selon les documents que j'ai essayés par
acquérir une référence au Fragment à partir de FragmentManager, en utilisant findFragmentById () ou findFragmentByTag ()
mais je ne connais pas la balise ou l'identifiant de mes fragments! J'ai un android: id = "@ + id / viewpager" pour ViewPager, et un android: id = "@ android: id / list" pour mon ListView dans la mise en page ListFragment, mais je ne pense pas que ceux-ci soient utiles.
Alors, comment puis-je: a) mettre à jour l'intégralité du ViewPager en toute sécurité en une seule fois (idéalement en renvoyant l'utilisateur à la page sur laquelle il se trouvait auparavant) - il est normal que l'utilisateur voit la vue changer. Ou de préférence, b) appelez une fonction dans chaque ListFragment affecté pour mettre à jour le ListView manuellement.
Toute aide serait acceptée avec gratitude!
null
fragment.FragmentPagerAdaper
mais échoue pourFragmentStatePagerAdaper
(Fragment.getTag()
toujours revenirnull
.La réponse de Barkside fonctionne avec
FragmentPagerAdapter
mais ne fonctionne pas avecFragmentStatePagerAdapter
, car elle ne définit pas de balises sur les fragments auxquels elle passeFragmentManager
.Avec
FragmentStatePagerAdapter
il semble que nous pouvons nous en sortir, en utilisant soninstantiateItem(ViewGroup container, int position)
appel. Il renvoie la référence au fragment à la positionposition
. SiFragmentStatePagerAdapter
contient déjà la référence au fragment en question,instantiateItem
renvoie simplement la référence à ce fragment et n'appelle pasgetItem()
pour l'instancier à nouveau.Supposons donc que je regarde actuellement le fragment # 50 et que je souhaite accéder au fragment # 49. Comme ils sont proches, il y a de fortes chances que le # 49 soit déjà instancié. Alors,
la source
FragmentStatePagerAdapter
, utiliser le code ci-dessus aveca.instantiateItem(viewPager, viewPager.getCurrentItem());
(pour se débarrasser du 49) comme proposé par @ mblackwell8 fonctionne parfaitement.instantiateItem
doivent être entourés destartUpdate
/finishUpdate
calls. les détails sont dans ma réponse à une question similaire: stackoverflow.com/questions/14035090/…OK, je pense avoir trouvé un moyen d'exécuter la demande b) dans ma propre question afin que je partage pour le bénéfice des autres. La balise des fragments à l'intérieur d'un ViewPager est dans le formulaire
"android:switcher:VIEWPAGER_ID:INDEX"
, oùVIEWPAGER_ID
est la miseR.id.viewpager
en page XML, et INDEX est la position dans le viewpager. Donc si la position est connue (par exemple 0), je peux jouer dansupdateFragments()
:Je ne sais pas si c'est une façon valable de le faire, mais cela fonctionnera jusqu'à ce que quelque chose de mieux soit suggéré.
la source
makeFragmentName
utilisée pour générer la balise que vous pouvez utiliser à la place pour une approche légèrement moins hacky:HomeListFragment fragment = (HomeListFragment) getSupportFragmentManager().findFragmentByTag(FragmentPagerAdapter.makeFragmentName(R.id.viewpager, 0));
makeFragmentName
est uneprivate static
méthode, vous ne pouvez donc pas y accéder.Si vous me le demandez, la deuxième solution sur la page ci-dessous, garder une trace de toutes les pages de fragments "actives", est meilleure: http://tamsler.blogspot.nl/2011/11/android-viewpager-and-fragments-part -ii.html
La réponse de barkside est trop hacky pour moi.
vous gardez une trace de toutes les pages de fragments "actives". Dans ce cas, vous effectuez le suivi des pages de fragment dans le FragmentStatePagerAdapter, qui est utilisé par le ViewPager.
Pour éviter de conserver une référence à des pages de fragment "inactives", nous devons implémenter la méthode destroyItem (...) de FragmentStatePagerAdapter:
... et lorsque vous avez besoin d'accéder à la page actuellement visible, vous appelez alors:
... où la méthode getFragment (int) de MyAdapter ressemble à ceci:
"
la source
D'accord, après avoir testé la méthode par @barkside ci-dessus, je n'ai pas pu la faire fonctionner avec mon application. Ensuite, je me suis souvenu que l' application IOSched2012 utilisait également un
viewpager
, et c'est là que j'ai trouvé ma solution. Il n'utilise aucun ID de fragment ou balise car ceux-ci ne sont pas stockés deviewpager
manière facilement accessible.Voici les parties importantes des applications IOSched HomeActivity. Portez une attention particulière au commentaire , car c'est là que réside la clé:
Et stockez les instances de vous
Fragments
de laFragmentPagerAdapter
même manière:N'oubliez pas non plus de garder vos
Fragment
appels comme ceci:la source
getItem()
ne pas être appelé après la recréation du parent en raison d'un changement de cycle de vie. Voir stackoverflow.com/a/24662049/236743 . Dans l'exemple, cela est en partie protégé pour un fragment mais pas pour les deux autresVous pouvez copier
FragmentPagerAdapter
et modifier du code source, ajouter unegetTag()
méthodepar exemple
puis étendez-le, remplacez ces méthodes abstraites, n'avez pas besoin d'avoir peur du changement de groupe Android
FragmentPageAdapter
code source dans le futurla source
Fonctionne également sans problèmes:
quelque part dans la mise en page du fragment de page:
dans onCreateView () du fragment:
et méthode pour renvoyer Fragment depuis ViewPager, s'il existe:
la source
Vous pouvez également remplacer la
setPrimaryItem
méthodeFragmentPagerAdapter
comme suit:la source
Je veux donner mon approche au cas où cela pourrait aider quelqu'un d'autre:
Voici mon adaptateur de téléavertisseur:
Dans mon activité j'ai:
Ensuite, pour obtenir le fragment actuel, ce que je fais est:
la source
C'est ma solution car je n'ai pas besoin de garder une trace de mes onglets et de les actualiser de toute façon.
la source