fragment android - Comment sauvegarder des états de vues dans un fragment quand un autre fragment est poussé sur le dessus de celui-ci

dans android, un fragment (dire FragA ) est ajouté dans les coulisses et un autre fragment (dire FragB ) arrive au sommet. Maintenant, sur frapper en arrière FragA vient au sommet et le onCreateView() s'appelle. Maintenant j'avais FragA dans un état particulier avant que FragB soit poussé dessus.

ma Question Est de savoir comment restaurer FragA à son état antérieur ? Est-il un moyen d'enregistrer l'état (comme, disons, dans un ensemble) et si oui, alors qui méthode dois-je remplacer ?

127
demandé sur pankajagarwal 2011-07-22 11:45:33

11 réponses

Fragment onSaveInstanceState(Bundle outState) ne sera jamais appelé à moins que l'activité du fragment l'appelle sur lui-même et les fragments attachés. Ainsi, cette méthode ne sera pas appelée jusqu'à ce que quelque chose (typiquement la rotation) force l'activité à SaveInstanceState et la restaurer plus tard. Mais si vous avez une seule activité et un grand ensemble de fragments à l'intérieur (avec une utilisation intensive de replace ) et l'application ne court que dans une seule activité d'orientation onSaveInstanceState(Bundle outState) peut ne pas être appelé pendant une longue période.

Je connais trois solutions possibles.

Le premier:

utiliser les arguments de fragment pour contenir des données importantes:

public class FragmentA extends Fragment {
    private static final String PERSISTENT_VARIABLE_BUNDLE_KEY = "persistentVariable";

    private EditText persistentVariableEdit;

    public FragmentA() {
        setArguments(new Bundle());
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment_a, null);

        persistentVariableEdit = (EditText) view.findViewById(R.id.editText);

        TextView proofTextView = (TextView) view.findViewById(R.id.textView);

        Bundle mySavedInstanceState = getArguments();
        String persistentVariable = mySavedInstanceState.getString(PERSISTENT_VARIABLE_BUNDLE_KEY);

        proofTextView.setText(persistentVariable);


        view.findViewById(R.id.btnPushFragmentB).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                getFragmentManager()
                        .beginTransaction()
                        .replace(R.id.frameLayout, new FragmentB())
                        .addToBackStack(null)
                        .commit();
            }
        });

        return view;
    }

    @Override
    public void onPause() {
        super.onPause();
        String persistentVariable = persistentVariableEdit.getText().toString();

        getArguments().putString(PERSISTENT_VARIABLE_BUNDLE_KEY, persistentVariable);
    }
}

La seconde, mais moins pédantesque - maintenez les variables dans les singletons

le troisième - ne pas replace() fragments mais add() / show() / hide() eux à la place.

75
répondu Fyodor Volchyok 2014-08-01 07:51:31
issue ici

20
répondu e_v_e 2017-05-23 11:33:24

gonflez votre vue pour une fois.

Exemple:

public class AFragment extends Fragment {

private View mRootView;
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    if(mRootView==null){
        mRootView = inflater.inflate(R.id.fragment_a, container, false);
        //......
    }
    return mRootView;
}

}

11
répondu Lym Zoy 2016-10-11 06:48:38

j'ai travaillé sur un sujet très similaire à celui-ci. Comme je savais que je retournerais souvent à un fragment précédent, j'ai vérifié si le fragment .isAdded() était vrai, et si oui, plutôt que de faire un transaction.replace() je fais juste un transaction.show() . Cela empêche le fragment d'être recréé s'il est déjà sur la pile - aucune sauvegarde d'état n'est nécessaire.

Fragment target = <my fragment>;
FragmentTransaction transaction = getFragmentManager().beginTransaction();
transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
if(target.isAdded()) {
    transaction.show(target);
} else {
    transaction.addToBackStack(button_id + "stack_item");
    transaction.replace(R.id.page_fragment, target);
}
transaction.commit();

une Autre chose à garder à l'esprit est que, bien que cela préserve l'ordre naturel pour fragments eux-mêmes, vous pourriez encore avoir besoin de gérer l'activité elle-même étant détruit et recréé sur le changement d'orientation (config). Pour contourner ça dans AndroidManifest.xml pour votre noeud:

android:configChanges="orientation|screenSize"

dans Android 3.0 et supérieur, le screenSize est apparemment requis.

bonne chance

8
répondu rmirabelle 2012-10-26 14:29:54

la meilleure Solution que j'ai trouvée est ci-dessous:

onSavedInstanceState (): toujours appelé inside fragment quand l'activité va s'arrêter (déplacement de l'activité de l'un à l'autre ou changements de configuration). Donc, si nous appelons plusieurs fragments sur la même activité, nous devons utiliser l'approche suivante:

utilisez OnDestroyView() du fragment et sauvegardez l'objet entier à l'intérieur de cette méthode. Puis OnActivityCreated (): vérifiez que si l'objet est nul ou pas(Parce que cette méthode appelle à chaque fois). Maintenant restaurer l'état d'un objet ici.

Sa fonctionne toujours!

5
répondu Aman Goel 2016-02-08 11:51:41

si vous manipulez les changements de configuration dans votre activité de fragment spécifiée dans Android manifest comme ceci ""

<activity
    android:name=".courses.posts.EditPostActivity"
    android:configChanges="keyboardHidden|orientation"
    android:screenOrientation="unspecified" />

alors le onSaveInstanceState du fragment ne sera pas invoqué et l'objet savedInstanceState sera toujours nul.

4
répondu Brook Oldre 2015-02-03 11:03:00

j'ai utilisé une approche hybride pour les fragments contenant une vue Liste. Il semble être performant puisque je ne remplace pas le fragment courant mais plutôt ajouter le nouveau fragment et cacher le courant. J'ai la méthode suivante dans l'activité qui héberge mes fragments:

public void addFragment(Fragment currentFragment, Fragment targetFragment, String tag) {
    FragmentManager fragmentManager = getSupportFragmentManager();
    FragmentTransaction transaction = fragmentManager.beginTransaction();
    transaction.setCustomAnimations(0,0,0,0);
    transaction.hide(currentFragment);
    // use a fragment tag, so that later on we can find the currently displayed fragment
    transaction.add(R.id.frame_layout, targetFragment, tag)
            .addToBackStack(tag)
            .commit();
}

j'utilise cette méthode dans mon fragment (contenant la vue Liste) chaque fois qu'un élément de liste est cliqué/tapé (et donc je dois lancer/afficher le fragment de détails):

FragmentManager fragmentManager = getActivity().getSupportFragmentManager();
SearchFragment currentFragment = (SearchFragment) fragmentManager.findFragmentByTag(getFragmentTags()[0]);
DetailsFragment detailsFragment = DetailsFragment.newInstance("some object containing some details");
((MainActivity) getActivity()).addFragment(currentFragment, detailsFragment, "Details");

getFragmentTags() renvoie un tableau de chaînes que j'utilise comme balises pour différents fragments lorsque j'ajoute un nouveau fragment (voir transaction.add méthode dans addFragment méthode ci-dessus).

dans le fragment contenant la vue Liste, je le fais dans sa méthode onPause ():

@Override
public void onPause() {
    // keep the list view's state in memory ("save" it) 
    // before adding a new fragment or replacing current fragment with a new one
    ListView lv =  (ListView) getActivity().findViewById(R.id.listView);
    mListViewState = lv.onSaveInstanceState();
    super.onPause();
}

puis dans onCreateView du fragment (en fait dans une méthode qui est invoquée dans onCreateView), je restaure l'état:

// Restore previous state (including selected item index and scroll position)
if(mListViewState != null) {
    Log.d(TAG, "Restoring the listview's state.");
    lv.onRestoreInstanceState(mListViewState);
}
0
répondu Javad Sadeqzadeh 2015-06-29 20:26:39

Je ne pense pas que onSaveInstanceState soit une bonne solution. il n'est utilisé que pour des activités qui ont été détruites.

d'android 3.0 Le Fragmen a été gestionnaire par FragmentManager, la condition est: une activité cartographie fragments manny, lorsque le fragment est ajouté(Non remplacer: il sera recréé) dans backStack, la vue sera détruit. quand retour à la dernière, il s'affichera comme avant.

donc je pense que le fragmentManger et transaction est bon assez pour la gérer.

0
répondu smallfatter 2016-04-20 03:43:46

à la fin après avoir essayé beaucoup de ces solutions compliquées que j'ai seulement eu besoin de sauver/restaurer une seule valeur dans mon Fragment( le contenu D'un texte D'édition), et bien qu'il puisse ne pas être la solution la plus élégante, la création d'un SharedPreference et de stocker mon état là travaillé pour moi

0
répondu VMMF 2016-05-25 21:16:57
private ViewPager viewPager;
viewPager = (ViewPager) findViewById(R.id.pager);
mAdapter = new TabsPagerAdapter(getSupportFragmentManager());
viewPager.setAdapter(mAdapter);
viewPager.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {

        @Override
        public void onPageSelected(int position) {
            // on changing the page
            // make respected tab selected
            actionBar.setSelectedNavigationItem(position);
        }

        @Override
        public void onPageScrolled(int arg0, float arg1, int arg2) {
        }

        @Override
        public void onPageScrollStateChanged(int arg0) {
        }
    });
}

@Override
public void onTabReselected(Tab tab, FragmentTransaction ft) {
}

@Override
public void onTabSelected(Tab tab, FragmentTransaction ft) {
    // on tab selected
    // show respected fragment view
    viewPager.setCurrentItem(tab.getPosition());
}

@Override
public void onTabUnselected(Tab tab, FragmentTransaction ft) {
}
-1
répondu Sathish 2014-12-09 13:59:45