web-dev-qa-db-de.com

Android - Fragmentstatus speichern / wiederherstellen

Ich habe eine Aktivität, in der ich mehrere Fragmente durchlaufe. In jedem Fragment habe ich mehrere Ansichten (EditText, ListView, Map Usw.).

Wie kann ich die Instanz des gerade angezeigten Fragments speichern? Ich brauche es, um zu arbeiten, wenn die Aktivität onPause() --> onResume() ist. Außerdem muss es funktionieren, wenn ich von einem anderen Fragment zurückkomme (Pop from Backstack).

Vom Hauptfragment Activity rufe ich das erste Fragment auf, dann vom Fragment das nächste.

Code für meine Aktivität:

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

Dann ist hier der Code für eines meiner Fragmente:

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

            });
        }}

Ich habe viele Informationen gesucht, aber nichts klares. Kann jemand bitte eine klare Lösung und ein Beispiel geben?

43
Stanete

Wenn ein Fragment in den Backstack verschoben wird, wird es nicht zerstört. Alle Instanzvariablen bleiben dort. Hier können Sie also Ihre Daten speichern. In onActivityCreated prüfen Sie folgende Bedingungen:

  1. Ist das Bundle! = Null? Wenn ja, werden die Daten dort gespeichert (wahrscheinlich Änderung der Ausrichtung).
  2. Werden Daten in Instanzvariablen gespeichert? Wenn ja, stellen Sie Ihren Zustand wieder her (oder tun Sie nichts, weil alles so ist, wie es sein sollte).
  3. Ansonsten wird dein Fragment zum ersten Mal angezeigt, erstelle alles neu.

Bearbeiten: Hier ist ein Beispiel

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();
            }
        }
    }
}
81
Kirill Rakhman

Android-Fragment hat einige Vor- und einige Nachteile. Der größte Nachteil des Fragments besteht darin, dass Sie ein Fragment erstellen, wenn Sie es verwenden möchten. Wenn Sie es verwenden, wird jedes Mal onCreateView des Fragments aufgerufen. Wenn Sie den Status der Komponenten im Fragment beibehalten möchten, müssen Sie den Fragmentstatus speichern und den Status im nächsten Bild laden. Dies macht die Fragmentansicht etwas langsam und seltsam.

Ich habe eine Lösung gefunden und diese verwendet: "Alles ist großartig. Jeder Körper kann es versuchen".

Wenn Sie onCreateView zum ersten Mal ausführen, erstellen Sie die Ansicht als globale Variable. Wenn Sie dieses Fragment zum zweiten Mal aufrufen onCreateView, können Sie diese globale Ansicht zurückgeben. Der Fragmentkomponentenstatus wird beibehalten.

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);
}
16
nebyan

Versuche dies :

@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();
}

Hoffe das wird helfen.

Sie können dies auch in das Aktivitäts-Tag in der Menifest-Datei schreiben:

  Android:configChanges="orientation|screenSize"

Viel Glück !!!

7
Sar

Um den Fragmentstatus zu speichern, müssen Sie onSaveInstanceState() implementieren: "Ebenso wie bei einer Aktivität können Sie den Status eines Fragments mithilfe eines Bundles beibehalten, falls der Prozess der Aktivität beendet wird und Sie den wiederherstellen müssen Fragmentstatus, wenn die Aktivität neu erstellt wird Sie können den Status während des onSaveInstanceState()-Rückrufs des Fragments speichern und ihn entweder während onCreate(), onCreateView() oder onActivityCreated(). Weitere Informationen zum Speichern des Status finden Sie im Dokument "Aktivitäten". "

http://developer.Android.com/guide/components/fragments.html#Lifecycle

4
Raanan

Wie hier angegeben: Warum Fragment # setRetainInstance (boolean) verwenden?

sie können auch die Fragmentmethode setRetainInstance(true) wie folgt verwenden:

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

    }
}
4
Richard R

Sie können das aktuelle Fragment aus fragmentManager abrufen. Und wenn es im Fragment-Manager keine gibt, können Sie Fragment_1 Erstellen.

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


    }


}

sie können auch setRetainInstance verwenden, um die Funktion zu ignorieren. Die Methode onDestroy() wird fragmentiert, und Ihre Anwendung geht in den Hintergrund, und Sie beenden Ihre Anwendung, um mehr Speicher zuzuweisen, den Sie zum Speichern benötigen Daten, die Sie in onSaveInstanceState Bundle benötigen

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

Ich bin mir nicht ganz sicher, ob Sie diese Frage noch immer beschäftigt, da es einige Monate her ist. Aber ich möchte mitteilen, wie ich damit umgegangen bin. Hier ist der Quellcode:

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

Und hier ist die MainActivity:

/**
 * 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;
    }
}

Das parentView ist der Schlüsselpunkt. Normalerweise verwenden wir bei onCreateView nur return rootView. Aber jetzt füge ich rootView zu parentView hinzu und gebe dann parentView zurück. Um zu verhindern, dass das angegebene untergeordnete Element bereits ein übergeordnetes Element hat. Sie müssen removeView() für den Fehler ... aufrufen. Sie müssen parentView.removeView(rootView) aufrufen, oder die von mir angegebene Methode ist unbrauchbar. Ich möchte auch mitteilen, wie ich es gefunden habe. Zunächst habe ich einen Booleschen Wert eingerichtet, der angibt, ob die Instanz vorhanden ist. Wenn die Instanz existiert, wird rootView nicht erneut aufgeblasen. Aber dann gab logcat an, dass das Kind bereits ein übergeordnetes Element hat, und ich entschied mich, ein anderes übergeordnetes Element als übergeordnete Zwischenansicht zu verwenden. So funktioniert das.

Hoffe es ist hilfreich für dich.

0
butch