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 ?

37
demandé sur David Silva-Barrera 2014-03-19 16:07:01

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:

  1. est le paquet != null? Si oui, c'est là que les données sont sauvegardées (probablement changement d'orientation).
  2. 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).
  3. 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();
            }
        }
    }
}
76
répondu Kirill Rakhman 2014-03-19 12:44:55

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);
}
14
répondu nebyan 2018-07-27 08:34:01

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 !!!

8
répondu Sar 2016-08-11 07:53:48

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);

    }
}
3
répondu Richard R 2017-05-23 12:10:11

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

3
répondu Raanan 2016-08-17 14:52:55

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.

0
répondu butch 2016-08-17 15:42:12

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");
    }

}
0
répondu Constantin Cerberus 2016-09-02 08:31:00