Android-enregistrer / restaurer l'état du fragment
j'ai une Activité dans laquelle je passe par plusieurs fragments. Dans chaque fragment j'ai plusieurs vues ( EditText, ListView, Map
, etc).
Comment puis-je sauvegarder l'instance du fragment qui est montré à ce moment? J'en ai besoin pour fonctionner quand l'activité est onPause() --> onResume()
. J'ai aussi besoin que ça marche quand je reviens d'un autre fragment (pop de backstack).
à Partir de la Activity
j'appelle le premier fragment, puis de la le fragment que j'appelle le suivant un.
Code de mon activité:
public class Activity_Main extends FragmentActivity{
public static Fragment_1 fragment_1;
public static Fragment_2 fragment_2;
public static Fragment_3 fragment_3;
public static FragmentManager fragmentManager;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
fragment_1 = new Fragment_1();
fragment_2 = new Fragment_2();
fragment_3 = new Fragment_3();
fragmentManager = getSupportFragmentManager();
FragmentTransaction transaction_1 = fragmentManager.beginTransaction();
transaction_1.replace(R.id.content_frame, fragment_1);
transaction_1.commit();
}}
alors voici le code pour un de mes fragments:
public class Fragment_1 extends Fragment {
private EditText title;
private Button go_next;
@Override
public View onCreateView(final LayoutInflater inflater,
ViewGroup container, Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_1,
container, false);
title = (EditText) rootView.findViewById(R.id.title);
go_next = (Button) rootView.findViewById(R.id.go_next);
image.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
FragmentTransaction transaction_2 = Activity_Main.fragmentManager
.beginTransaction();
transaction_2.replace(R.id.content_frame,
Activity_Main.fragment_2);
transaction_2.addToBackStack(null);
transaction_2.commit();
});
}}
j'ai cherché beaucoup d'informations mais rien de clair. Quelqu'un peut-il donner une solution claire et un exemple, s'il vous plaît ?
7 réponses
Lorsqu'un fragment est déplacé dans les coulisses, il n'est pas détruit. Toutes les variables d'instance restent là. Voici donc l'endroit pour sauvegarder vos données. Dans onActivityCreated
vous vérifiez les conditions suivantes:
- est le paquet != null? Si oui, c'est là que les données sont sauvegardées (probablement changement d'orientation).
- y a-t-il des données enregistrées dans les variables d'instance? Si oui, restaurez votre état à partir d'eux (ou peut-être ne rien faire, parce que tout est comme il devrait être).
- sinon votre fragment est montré pour la première fois, créer tout à nouveau.
Edit: voici un exemple
public class ExampleFragment extends Fragment {
private List<String> myData;
@Override
public void onSaveInstanceState(final Bundle outState) {
super.onSaveInstanceState(outState);
outState.putSerializable("list", (Serializable) myData);
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
if (savedInstanceState != null) {
//probably orientation change
myData = (List<String>) savedInstanceState.getSerializable("list");
} else {
if (myData != null) {
//returning from backstack, data is fine, do nothing
} else {
//newly created, compute data
myData = computeData();
}
}
}
}
fragment Android a certains avantages et certains inconvénients.
Le principal inconvénient du fragment est que lorsque vous voulez utiliser un fragment, vous le créez.
Lorsque vous l'utilisez, onCreateView
du fragment est appelé à chaque fois. Si vous voulez garder l'état des composants dans le fragment, vous devez sauvegarder l'état du fragment et vous devez charger son état dans le prochain montré.
Cela rend la vue de fragment un peu lente et bizarre.
j'ai trouvé une solution et j'ai utilisé cette solution: "tout est super. Chaque corps peut essayer".
lorsque la première fois onCreateView
est lancé, créer la vue comme une variable globale. Lorsque la deuxième fois que vous appelez ce fragment onCreateView
est appelé à nouveau, vous pouvez retourner cette vue globale. L'état du composant fragment sera conservé.
View view;
@Override
public View onCreateView(LayoutInflater inflater,
@Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
setActionBar(null);
if (view != null) {
if ((ViewGroup)view.getParent() != null)
((ViewGroup)view.getParent()).removeView(view);
return view;
}
view = inflater.inflate(R.layout.mylayout, container, false);
}
essayez ceci:
@Override
protected void onPause() {
super.onPause();
if (getSupportFragmentManager().findFragmentByTag("MyFragment") != null)
getSupportFragmentManager().findFragmentByTag("MyFragment").setRetainInstance(true);
}
@Override
protected void onResume() {
super.onResume();
if (getSupportFragmentManager().findFragmentByTag("MyFragment") != null)
getSupportFragmentManager().findFragmentByTag("MyFragment").getRetainInstance();
}
Espérons que cela aidera.
vous pouvez aussi écrire ceci à l'étiquette d'activité dans le fichier menifest:
android:configChanges="orientation|screenSize"
bonne chance !!!
comme indiqué ici: Pourquoi utiliser le Fragment#setRetainInstance (booléen)?
vous pouvez également utiliser la méthode des fragments setRetainInstance(true)
comme ceci:
public class MyFragment extends Fragment {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// keep the fragment and all its data across screen rotation
setRetainInstance(true);
}
}
pour sauvegarder l'état du Fragment, vous devez implémenter onSaveInstanceState()
:
"Aussi comme une activité, vous pouvez conserver l'état d'un fragment à l'aide d'un faisceau, au cas où le processus de l'activité est tué et vous devez restaurer l'état du fragment lorsque l'activité est recréée. Vous pouvez sauvegarder l'état lors de l'appel onSaveInstanceState()
du fragment et le restaurer lors de onCreate()
, onCreateView()
, ou onActivityCreated()
. Pour plus d'informations sur l'état de sauvegarde, consultez le document activités."
http://developer.android.com/guide/components/fragments.html#Lifecycle
Je ne suis pas tout à fait sûr que cette question vous dérange encore, puisqu'elle a été plusieurs mois. Mais je voudrais partager comment j'ai traité ce. Voici le code source:
int FLAG = 0;
private View rootView;
private LinearLayout parentView;
/**
* The fragment argument representing the section number for this fragment.
*/
private static final String ARG_SECTION_NUMBER = "section_number";
/**
* Returns a new instance of this fragment for the given section number.
*/
public static Fragment2 newInstance(Bundle bundle) {
Fragment2 fragment = new Fragment2();
Bundle args = bundle;
fragment.setArguments(args);
return fragment;
}
public Fragment2() {
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
super.onCreateView(inflater, container, savedInstanceState);
Log.e("onCreateView","onCreateView");
if(FLAG!=12321){
rootView = inflater.inflate(R.layout.fragment_create_new_album, container, false);
changeFLAG(12321);
}
parentView=new LinearLayout(getActivity());
parentView.addView(rootView);
return parentView;
}
/* (non-Javadoc)
* @see android.support.v4.app.Fragment#onDestroy()
*/
@Override
public void onDestroy() {
// TODO Auto-generated method stub
super.onDestroy();
Log.e("onDestroy","onDestroy");
}
/* (non-Javadoc)
* @see android.support.v4.app.Fragment#onStart()
*/
@Override
public void onStart() {
// TODO Auto-generated method stub
super.onStart();
Log.e("onstart","onstart");
}
/* (non-Javadoc)
* @see android.support.v4.app.Fragment#onStop()
*/
@Override
public void onStop() {
// TODO Auto-generated method stub
super.onStop();
if(false){
Bundle savedInstance=getArguments();
LinearLayout viewParent;
viewParent= (LinearLayout) rootView.getParent();
viewParent.removeView(rootView);
}
parentView.removeView(rootView);
Log.e("onStop","onstop");
}
@Override
public void onPause() {
super.onPause();
Log.e("onpause","onpause");
}
@Override
public void onResume() {
super.onResume();
Log.e("onResume","onResume");
}
Et voici L'activité principale:
/**
* Fragment managing the behaviors, interactions and presentation of the
* navigation drawer.
*/
private NavigationDrawerFragment mNavigationDrawerFragment;
/**
* Used to store the last screen title. For use in
* {@link #restoreActionBar()}.
*/
public static boolean fragment2InstanceExists=false;
public static Fragment2 fragment2=null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
setContentView(R.layout.activity_main);
mNavigationDrawerFragment = (NavigationDrawerFragment) getSupportFragmentManager()
.findFragmentById(R.id.navigation_drawer);
mTitle = getTitle();
// Set up the drawer.
mNavigationDrawerFragment.setUp(R.id.navigation_drawer,
(DrawerLayout) findViewById(R.id.drawer_layout));
}
@Override
public void onNavigationDrawerItemSelected(int position) {
// update the main content by replacing fragments
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction=fragmentManager.beginTransaction();
switch(position){
case 0:
fragmentTransaction.addToBackStack(null);
fragmentTransaction.replace(R.id.container, Fragment1.newInstance(position+1)).commit();
break;
case 1:
Bundle bundle=new Bundle();
bundle.putInt("source_of_create",CommonMethods.CREATE_FROM_ACTIVITY);
if(!fragment2InstanceExists){
fragment2=Fragment2.newInstance(bundle);
fragment2InstanceExists=true;
}
fragmentTransaction.addToBackStack(null);
fragmentTransaction.replace(R.id.container, fragment2).commit();
break;
case 2:
fragmentTransaction.addToBackStack(null);
fragmentTransaction.replace(R.id.container, FolderExplorerFragment.newInstance(position+1)).commit();
break;
default:
break;
}
}
Le parentView
est le point-clé.
Normalement, quand onCreateView
, nous utilisons juste rootView
. Mais maintenant, j'ajoute rootView à parentView
, puis je renvoie parentView
. Pour éviter "L' l'enfant désigné a déjà un parent. Vous devez appeler removeView()
sur le ..."erreur, il faut appeler parentView.removeView(rootView)
, ou la méthode que j'ai fournie est inutile.
Je voudrais aussi partager comment je l'ai trouvé. Premièrement, j'ai mis en place un booléen pour indiquer si l'instance existe. Lorsque l'instance existe, le rootView
ne sera plus gonflé. Mais ensuite, logcat a donné à l'enfant a déjà une chose de parent, donc j'ai décidé d'utiliser un autre parent comme une vue de Parent intermédiaire. C'est la façon dont il fonctionne.
J'espère que ça vous aidera.
vous pouvez obtenir le Fragment courant de fragmentManager. Et s'il n'y en a pas dans fragment manager, vous pouvez créer Fragment_1
public class MainActivity extends FragmentActivity {
public static Fragment_1 fragment_1;
public static Fragment_2 fragment_2;
public static Fragment_3 fragment_3;
public static FragmentManager fragmentManager;
@Override
protected void onCreate(Bundle arg0) {
super.onCreate(arg0);
setContentView(R.layout.main);
fragment_1 = (Fragment_1) fragmentManager.findFragmentByTag("fragment1");
fragment_2 =(Fragment_2) fragmentManager.findFragmentByTag("fragment2");
fragment_3 = (Fragment_3) fragmentManager.findFragmentByTag("fragment3");
if(fragment_1==null && fragment_2==null && fragment_3==null){
fragment_1 = new Fragment_1();
fragmentManager.beginTransaction().replace(R.id.content_frame, fragment_1, "fragment1").commit();
}
}
}
aussi, vous pouvez utiliser setRetainInstance
à vrai ce qu'il fera ignorer onDestroy()
méthode dans fragment et votre application va à l'arrière-plan et os tuer votre application pour allouer plus de mémoire, vous aurez besoin de sauvegarder toutes les données dont vous avez besoin dans onSaveInstanceState
bundle
public class Fragment_1 extends Fragment {
private EditText title;
private Button go_next;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRetainInstance(true); //Will ignore onDestroy Method (Nested Fragments no need this if parent have it)
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
onRestoreInstanceStae(savedInstanceState);
return super.onCreateView(inflater, container, savedInstanceState);
}
//Here you can restore saved data in onSaveInstanceState Bundle
private void onRestoreInstanceState(Bundle savedInstanceState){
if(savedInstanceState!=null){
String SomeText = savedInstanceState.getString("title");
}
}
//Here you Save your data
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putString("title", "Some Text");
}
}