The best way to save and restore fragment status in Android

Source: Internet
Author: User

English Original: Probably is the best (?) to Save/restore Android Fragment ' s

Key points: Fragment's arguments.

After years of using fragment, I want to say that fragment is really a smart design, but there are too many problems to be solved by using fragment, especially when dealing with data retention.

First, although it has an activity-like onsaveinstancestate, don't think you can keep the data just by Onsaveinstancestate.

Here are some examples:

Scenario One: Rotate the screen when there is only one fragment in the stack

Yes, rotating the screen is the easiest way to test data. This is a very simple situation, and you simply need to store the data that will be lost when the onsaveinstancestate is rotated, including the variable, and then take it out in the onactivitycreated or onviewstaterestored:

int somevar; @Overrideprotected void Onsaveinstancestate (Bundle outstate) {   outstate.putint ("Somevar", Somevar);   Outstate.putstring ("Text", Tv1.gettext (). toString ());} @Overridepublic void onactivitycreated (Bundle savedinstancestate) {   super.onactivitycreated (savedinstancestate );   Somevar = Savedinstancestate.getint ("Somevar", 0);   Tv1.settext (savedinstancestate.getstring ("text"));}

It seems simple, but there is a situation where the view is rebuilt, but Onsaveinstancestate is not called, which means that everything on the UI is lost, see the following case.

Scenario 2:Fragment return from the fallback stack

When Fragment returns from Backstack (this is Fragment a), the view in Fragment A is rebuilt according to the official document's description of the Fragment life cycle.

As you can see from this graph, when fragment returns from the fallback stack,Ondestroyview and Oncreateview are called, but Onsaveinstancestate doesn't seem to be called, This causes all UI data to go back to the initial state defined in the XML layout. Of course, those view that implement state preservation internally, such as EditText and TextView with the Android:freezetext attribute, can still remain in their state because fragment can keep the data for them, but developers can't get these events, We can only save this data manually in the Ondestroyview.

The approximate process is as follows:

@Overridepublic void Onsaveinstancestate (Bundle outstate) {   super.onsaveinstancestate (outstate);   Save data here} @Overridepublic void Ondestroyview () {   super.ondestroyview ();   If Onsaveinstancestate is not called, the data can also be saved here}

But here's the problem. Saving data in Onsaveinstancestate is simple because it has bundle parameters, but Ondestroyview no, where is it stored? The answer is a Argumentthat can coexist with fragment.

The code is roughly as follows:

bundle savedstate; @Overridepublic void onactivitycreated (bundle savedinstancestate) {super.onactivitycreated (   Savedinstancestate); Restore state here if (!restorestatefromarguments ()) {//First time running, Initialize something here}} @Ove   rridepublic void Onsaveinstancestate (Bundle outstate) {super.onsaveinstancestate (outstate); Save state here Savestatetoarguments ();}   @Overridepublic void Ondestroyview () {Super.ondestroyview (); Save state here Savestatetoarguments ();}   private void Savestatetoarguments () {savedstate = SaveState ();      if (savedstate! = null) {Bundle b = getarguments ();   B.putbundle ("internalSavedViewState8954201239547", savedstate);   }}private Boolean restorestatefromarguments () {Bundle b = getarguments ();   savedstate = B.getbundle ("internalSavedViewState8954201239547");      if (savedstate! = null) {restorestate ();   return true; } return false;} Remove Status Data////////////////////private void Restorestate () {if (savedstate! = null) {//such as//tv1.settext (Savedstate.getstring ("   Text ")); }}////////////////////////////////Save status Data//////////////////////////////private bundle SaveState () {Bundle state = new   Bundle ();   such as//state.putstring ("text", Tv1.gettext (). toString ()); return state;}

Now you can easily fragment in thesaveState和restoreState中分别存储和取出数据了。现在看起来好多了,几乎快要成功了,但是还有更极端的情况。

Scenario 3: Rotate two times when there is more than one fragment in the fallback stack

When you rotate the screen once, Onsaveinstancestate is called and the UI state is saved as expected, but when you rotate the screen again, the code above may crash. The reason is that although onsaveinstancestate is called, when you rotate the screen, the fragment view in the fallback stack is destroyed and will not be rebuilt until it is returned. This causes the view to save the data when you rotate the screen again. saveState()will refer to a nonexistent view resulting in a null pointer exception nullpointerexception, so you need to check that the view exists first. If there is data to save its state, save the data in argument again, or do nothing at all, because the first time it has been saved.

private void Savestatetoarguments () {   if (getView () = null)      savedstate = SaveState ();   if (savedstate! = null) {      Bundle B = getarguments ();      B.putbundle ("savedstate", savedstate);   }}


final template for fragment:

Here is the fragment template I'm using.

Import Android.os.bundle;import Android.support.v4.app.fragment;import Android.view.layoutinflater;import Android.view.view;import Android.view.ViewGroup; Import COM.INTHECHEESEFACTORY.THECHEESELIBRARY.R; /** * Created by Nuuneoi on 11/16/2014.     */public class Statedfragment extends Fragment {Bundle savedstate;    Public Statedfragment () {super (); } @Override public void onactivitycreated (Bundle savedinstancestate) {super.onactivitycreated (savedinstance        State);            Restore state here if (!restorestatefromarguments ()) {//-first time, Initialize something here        Onfirsttimelaunched (); }} protected void Onfirsttimelaunched () {} @Override public void Onsaveinstancestate (Bundle outstate)        {super.onsaveinstancestate (outstate);    Save state here savestatetoarguments ();        } @Override public void Ondestroyview () {Super.ondestroyview ();       Save State Here Savestatetoarguments ();    }//////////////////////Don ' t Touch!! private void Savestatetoarguments () {if (GetView () = null) savedstate = SaveS        Tate ();            if (savedstate! = null) {Bundle b = getarguments ();        B.putbundle ("internalSavedViewState8954201239547", savedstate);    }}//////////////////////Don ' t Touch!!        Private Boolean restorestatefromarguments () {Bundle b = getarguments ();        savedstate = B.getbundle ("internalSavedViewState8954201239547");            if (savedstate! = null) {restorestate ();        return true;    } return false;  }///////////////////////////////////Restore Instance state here/////////////////////////////////private void Restorestate () {if (savedstate! = null) {//For Example//tv1.settext (savedstate.gets            Tring ("text")); Onrestorestate (SAVedstate); }} protected void Onrestorestate (Bundle savedinstancestate) {}////////////////////////////////Save         Instance state this//////////////////////////////private bundle saveState () {Bundle state = new bundle ();        For Example//state.putstring ("text", Tv1.gettext (). toString ());        Onsavestate (state);    return state; } protected void Onsavestate (Bundle outstate) {}}

If you use this template, you simply inherit the StatedFragment class and then onSaveState() save the data,在onRestoreState()中取出数据,其余的事情上面的代码已经为你做好了,我相信覆盖了我所知道的所有情况。

Library

Now that the statedfragment described in this article has been made into an easy-to-use library and published to Jcenter, you can now simply add dependencies to the Build.gradle:

dependencies {    compile ' com.inthecheesefactory.thecheeselibrary:stated-fragment-support-v4:0.9.1 '}

Inherit Statedfragment, and onSaveState(Bundle outState) onRestoreState(Bundle savedInstanceState) save and remove state data separately in and. If you want to do something when the fragment first starts, you can also rewriteonFirstTimeLaunched(),它只会在第一次启动的时候被调用。

public class Mainfragment extends Statedfragment {     ...     /**     * Save Fragment ' s state here     *    /@Override protected void Onsavestate (Bundle outstate) {        Super.onsavestate (outstate);        For example:        //outstate.putstring ("text", Tvsample.gettext (). toString ());    }     /**     * Restore Fragment ' s state here     *    /@Override protected void Onrestorestate (Bundle Savedinstancestate) {        super.onrestorestate (savedinstancestate);        For example:        //tvsample.settext (savedinstancestate.getstring ("text"));    }     ... }

Reprint please specify the source http://jcodecraeer.com/a/anzhuokaifa/androidkaifa/2015/0327/2648.html

The best way to save and restore fragment status in Android

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.