J'ai une activité dans laquelle je traverse plusieurs fragments. Dans chaque fragment, j'ai plusieurs vues (EditText, ListView, Map
, Etc.).
Comment puis-je sauvegarder l'instance du fragment qui est affichée à ce moment? J'ai besoin que cela fonctionne lorsque l'activité est onPause() --> onResume()
. Aussi, j'ai besoin que ça fonctionne quand je reviens d'un autre fragment (pop de backstack).
À partir du Activity
principal, j'appelle le premier fragment, puis du fragment, j'appelle le suivant.
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?
Lorsqu'un fragment est déplacé dans le pile, il n'est pas détruit. Toutes les variables d'instance restent là. C'est donc l'endroit idéal pour sauvegarder vos données. Dans onActivityCreated
, vous vérifiez les conditions suivantes:
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();
}
}
}
}
Le fragment Android présente des avantages et des inconvénients. Le plus désavantage du fragment est que lorsque vous voulez utiliser un fragment, vous en créez un. Lorsque vous l'utilisez, onCreateView
du fragment est appelé à chaque fois. Si vous souhaitez conserver l’état des composants dans le fragment, vous devez enregistrer l’état du fragment et vous devez charger son état dans le suivant. Cela rend la vue fragmentée un peu lente et bizarre.
J'ai trouvé une solution et j'ai utilisé cette solution: "Tout va bien. Tout le monde peut essayer".
Lors de la première exécution de onCreateView
, créez la vue en tant que variable globale. Lorsque vous appelez ce fragment pour la deuxième fois, 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);
}
Essaye ça :
@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();
}
J'espère que cela aidera.
Vous pouvez aussi écrire ceci dans la balise activity dans le fichier menifest:
Android:configChanges="orientation|screenSize"
Bonne chance !!!
Afin de sauvegarder l’état du fragment, vous devez implémenter onSaveInstanceState()
: "De la même manière qu’une activité, vous pouvez conserver l’état d’un fragment à l’aide d’un ensemble, au cas où le processus de l’activité serait tué et que vous deviez restaurer le Etat du fragment lors de la recréation de l'activité.Vous pouvez enregistrer l'état pendant le rappel du fragment par le onSaveInstanceState()
du fragment et le restaurer au cours de onCreate()
, onCreateView()
ou onActivityCreated()
. Pour plus d'informations sur la sauvegarde de l'état, voir le document Activités. "
http://developer.Android.com/guide/components/fragments.html#Lifecycle
Comme indiqué ici: Pourquoi utiliser Fragment # setRetainInstance (boolean)?
vous pouvez aussi utiliser la méthode 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);
}
}
Vous pouvez obtenir le fragment actuel de fragmentManager. Et s'il n'y en a pas dans le gestionnaire de fragments, 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
pour true ce qu’il va faire ignorer la méthode onDestroy()
dans fragment et votre application en arrière-plan et tuer votre application pour allouer plus de mémoire dont vous aurez besoin pour tout sauvegarder 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");
}
}
Je ne suis pas tout à fait sûr si cette question vous dérange toujours, car cela fait plusieurs mois. Mais je voudrais partager comment j'ai traité avec cela. 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, lorsque onCreateView
, nous utilisons simplement return rootView
. Mais maintenant, j'ajoute rootView à parentView
, puis je retourne parentView
. Pour empêcher "L'enfant spécifié a déjà un parent. Vous devez appeler removeView()
sur l'erreur ...", nous devons appeler parentView.removeView(rootView)
ou la méthode que j'ai fournie est inutile. Je voudrais aussi partager comment je l'ai trouvé. Tout d'abord, j'ai mis en place un booléen pour indiquer si l'instance existe. Lorsque l'instance existe, le rootView
ne sera pas gonflé à nouveau. Mais alors, logcat a donné à l'enfant déjà un truc de parent, alors j'ai décidé d'utiliser un autre parent comme vue parent intermédiaire. Ça fonctionne comme ça.
J'espère que cela vous sera utile.