web-dev-qa-db-fra.com

La vue fragmentée dans ViewPager n'est pas restaurée lors de la reprise.

J'ai la configuration ActionBar Tabs. Il se compose de 4 onglets. Tout va bien jusqu'à ce que je quitte la TabbedFragment et que je revienne.

Je crée des onglets comme celui-ci:

  @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        final ActionBar actionBar = getActionBar();

        tabs = Lists.newArrayList();
        tabs.add(new TabDefinition<>("Tab 1"));
        tabs.add(new TabDefinition<>("Tab 2"));
        tabs.add(new TabDefinition<>("Tab 3"));
        tabs.add(new TabDefinition<>("Tab 4"));


        for (TabDefinition tab : tabs) {
            actionBar.addTab(actionBar.newTab()
                .setText(tab.text)
                .setTag(tab.tag)
                .setTabListener(this));
        }
    }

Et initialisez l'adaptateur comme ceci:

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    return inflater.inflate(R.layout.paging_tab_container, container, false);
}

@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
    super.onViewCreated(view, savedInstanceState);
    viewPager = (ViewPager) view.findViewById(R.id.pager);

    viewPager.setAdapter(new FragmentStatePagerAdapter(getFragmentManager()) {

        @Override
        public Fragment getItem(int position) {
            return tabs.get(position).fragment;
        }

        @Override
        public int getCount() {
            return tabs.size();
        }
    });

    viewPager.setOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
        @Override
        public void onPageSelected(int position) {
            getActionBar().setSelectedNavigationItem(position);
        }
    });

    viewPager.setCurrentItem(getActionBar().getSelectedNavigationIndex(), true);
}

En revenant à TabbedFragment onglet sélectionné et 1 à côté de celui-ci n'aura aucun contenu. Juste vue vide. Mais si je sélectionne + 2, le contenu du fragment est chargé. Et puis, le contenu de ce premier fragment est rechargé.
Par exemple, j'ai des onglets A, B, C, D. Avant de quitter TabbedFragment, j'avais sélectionné l'onglet A . Lorsque je suis retourné à TabbedFragment, je suis toujours à l'onglet A mais il est vide. Ainsi que l'onglet B.
Mais lors de la sélection de l'onglet C, il est créé et chargé. Revenant à l'onglet A, il est recréé.

Quel pourrait être le problème ici?

24
Martynas Jurkus

Après un certain temps, vous rencontrez à nouveau le même problème et vous devez donc mettre à jour cette question… .. Si vous utilisez FragmentStatePagerAdapter, vous devez fournir FragmentManager via getChildFragmentManager() au lieu de getFragmentManager(). See Issue 55068: ViewPager n’actualise pas les fragments enfants lors d’une navigation retour dans backstack

58
Martynas Jurkus

Si vous utilisez FragmentStatePagerAdapter, vos fragments seront détruits si vous parcourez plus d'un fragment absent, car par défaut, offScreenPageLimit est défini sur 1 par défaut, comme indiqué ci-dessus. 

En règle générale, cette classe est utilisée pour une activité comportant un très grand nombre de Fragments, c’est-à-dire qu’il faut faire défiler une grande quantité de vues. Si votre application n'a pas besoin de plus de 3 à 4 onglets, je vous suggèrerais plutôt d'utiliser FragmentPagerAdapter, puis de spécifier offScreenPageLimit à 3, donc si vous arrivez au 4e onglet, les 3 onglets précédents seront toujours en mémoire.

Voici un exemple de code pour un projet sur github que j’ai créé et illustrant la procédure de chargement dynamique des fragments si vous ne souhaitez pas ajouter ceci offScreenPageLimit.

https://github.com/lt-tibs1984/InterfaceDemo/blob/master/src/com/divshark/interfacedemo/InterfaceDemoMain.Java

Parcourez tout ce code dans cette classe et vous verrez comment je charge dynamiquement les fragments chaque fois que ma ViewPager est glissée. Plus particulièrement au bas. 

Vous pouvez télécharger ce code et l'utiliser comme base de test pour ce que vous voulez faire. Essayez d’ajouter setOffScreenPageLimit (2) à la méthode onCreate () pour le viewPager et notez le comportement différent. Pour vérifier le comportement, modifiez le texte dans le fragment 1. Naviguez vers l'arrière et revenez en arrière, avec cet ensemble ou non. Vous verrez quand il est défini, le texte du fragment reste ce que vous changez, car le fragment n'est jamais recréé.

S'il vous plaît fournir des questions supplémentaires si vous en avez.

Bonne chance

METTRE &AGRAVE; JOUR

private static final String [] fragmentClasses = {"com.example.project.YourFragment1","com.example.project.YourFragment2","com.example.project.YourFragment3"};



 viewPager.setAdapter(new FragmentStatePagerAdapter(getFragmentManager()) {

    @Override
    public Fragment getItem(int position) {

       Fragment fragmentAtPosition = null;

       // $$$$ This is the Important Part $$$$$
       // Check to make sure that your array is not null, size is greater than 0 , current position is greater than equal to 0, and position is less than length
       if((fragmentClasses != null) && (fragmentClasses.length > 0)&&(position >= 0)&& (position < fragmentClasses.length))
        {
       // Instantiate the Fragment at the current position of the Adapter
        fragmentAtPosition = Fragment.instantiate(getBaseContext(), fragmentClasses[position]);
        fragmentAtPosition.setRetainInstance(true);

       }

        return fragmentAtPosition;
    }

    @Override
    public int getCount() {
        return fragmentClasses.length;
    }
});
3
kandroidj

Le problème existe dans les fragments que vous utilisez comme onglets, je pense. Ils semblent ne rien montrer à la reprise (voir cycle de vie d'un fragment ). Le problème "étrange" selon lequel seul l'onglet +/- 1 actuellement sélectionné est vide est dû au fait que offScreenPageLimit de votre ViewPager est 1 par défaut. Tous les onglets supérieurs à ce seuil sont recréés.

Par conséquent, si vous augmentez la valeur, tous vos onglets apparaîtront vides après la reprise, dans votre cas. Vérifiez dans votre code de fragment les méthodes de cycle de vie que vous utilisez pour gonfler votre mise en page, définir des adaptateurs, etc., car c'est ce qui vous cause des problèmes.

1
saschoar

Je suppose que cela se produit car, lors du chargement du fragment, Android charge current et current + 1, si vous déboguez, vous ne verrez pas onPause être appelé pour le fragment suivant.

Vous pouvez recharger le contenu par programme dans la méthode onTabChanged () de TabHost.OnTabChangeListener.

0
techieWings

Après de nombreuses recherches, cela a fonctionné pour moi ………… .J'ai une mise en page complexe avec 3 onglets dans un fragment, qui est remplacé par d'autres fragments. J'ai réalisé que la ViewpagerAdapter conservera cet état, même si vous appuyez sur le bouton d'accueil. Mon problème était de basculer en arrière annulerait les éléments de vue de l'interface utilisateur de fragment enfant et planterait. La clé est de ne pas new sortir votre ViewPagerAdapter. L'ajout du contrôle nul pour l'adaptateur a fonctionné pour moi. Assurez-vous également d’allouer setOffscreenPageLimit() à vos besoins. De plus, d'après ce que j'ai compris, setRetainInstance(true); ne devrait pas être utilisé pour les fragments avec interface utilisateur, il est conçu pour les fragments sans tête.

Dans le fragment qui contient vos onglets:

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {
    // Inflate the layout for this fragment
    View view = inflater.inflate(R.layout.fragment_tab, container, false);
    tabLayout = (TabLayout) view.findViewById(R.id.tablayout);
    viewPager = (ViewPager) view.findViewById(R.id.viewPager);

    //Important!!! Do not fire the existing adapter!!
    if (viewPagerAdapter == null) {
        viewPagerAdapter = new ViewPagerAdapter(getChildFragmentManager());
        viewPagerAdapter.addFragments(new AFragment(), "A");
        viewPagerAdapter.addFragments(new BFragment(), "B");
        viewPagerAdapter.addFragments(new CFragment(), "C");
    }
    //Allocate retention buffers for three tabs, mandatory
    viewPager.setOffscreenPageLimit(3);
    tabLayout.setupWithViewPager(viewPager);
    viewPager.setAdapter(viewPagerAdapter);

    return view;
}
0
Len

Ou plus simplement lorsque vous revenez à tabbedfragment (en supposant que vous utilisez une intention et que le fragment se trouve dans une activité), utilisez:

intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);

Cela conserve l'activité d'origine et la déplace au sommet de la pile plutôt que de la recréer. Vous n'avez donc jamais besoin de recréer le viewPager.

0
Benjamin Roberts