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 ?
11 réponses
Dans fragment "guide de 151940920" FragmentList exemple, vous pouvez trouver:
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putInt("curChoice", mCurCheckPosition);
}
que vous pouvez utiliser plus tard comme ceci:
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
if (savedInstanceState != null) {
// Restore last state for checked position.
mCurCheckPosition = savedInstanceState.getInt("curChoice", 0);
}
}
je suis un débutant en Fragments mais il semble que la solution de votre problème ;) OnActivityCreated est invoqué après les retours de fragment de la pile arrière.
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.
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;
}
}
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
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!
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.
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);
}
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.
à 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
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) {
}