Activity与Fragment状态保存问题

翻译老外的文章,写的不错,也可以自己去看,地址。

1.Activity

Activity onSaveInstanceState被调用,Activity自动会按照View层级获取每一个View的状态信息。注意,Activity只能获取覆写了Saving/RestoringState方法的View 的状态。一旦onRestoreInstanceState被调用, Activity会按照View层级一个一个发送保存的状态至View(根据android:id判断不同的View

来看一下动态图!


Activity与Fragment状态保存问题_第1张图片

Activity与Fragment状态保存问题_第2张图片

这就是当Activity被摧毁重建而EditText输入的内容依然存在的原因。这并不是魔术,这些View的状态会自动保存并还原,这也是为什么一个View没有定义idandroid:id)的话状态会丢失的原因。

尽管这些View的状态会自动保存,Activity的成员变量却并不会。它们会随着Activity一同被摧毁,你必须手动覆写onSaveInstanceState onRestoreInstanceState方法来保存/还原它们。

public class MainActivity extends AppCompatActivity {
 
    // These variable are destroyed along with Activity
    private int someVarA;
    private String someVarB;
 
    ...
 
    @Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        outState.putInt("someVarA", someVarA);
        outState.putString("someVarB", someVarB);
    }
 
    @Override
    protected void onRestoreInstanceState(Bundle savedInstanceState) {
        super.onRestoreInstanceState(savedInstanceState);
        someVarA = savedInstanceState.getInt("someVarA");
        someVarB = savedInstanceState.getString("someVarB");
    }
 
}

这就是所有关于保存Activity状态和View状态你需要做的。 

2.Fragment

Fragment被系统摧毁/重建,这种情形基本上和Activity一致。 

Activity与Fragment状态保存问题_第3张图片

Activity与Fragment状态保存问题_第4张图片

这意味着每一个成员变量都会被摧毁,你必须手动通过onSaveInstanceState onActivityCreated方法保存/恢复这些变量,需要注意的是Fragment中没有提供 onRestoreInstanceState 方法。

public class MainFragment extends Fragment {
 
    // These variable are destroyed along with Activity
    private int someVarA;
    private String someVarB;
 
    ...
 
    @Override
    public void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        outState.putInt("someVarA", someVarA);
        outState.putString("someVarB", someVarB);
    }
 
    @Override
    public void onActivityCreated(@Nullable Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        someVarA = savedInstanceState.getInt("someVarA");
        someVarB = savedInstanceState.getString("someVarB");
    }
 
}

一旦Fragment从返回站中弹出,他的View会被摧毁和重建,这一点与Activity不同。

Activity与Fragment状态保存问题_第5张图片

在这种情况下,Fragment不会destroyed,只有Fragment中的 View才会。

所以要想保存View状态,View必须覆写Saving/RestoringState方法,例如EditTextTextView,只需加上android:freezeText="true",就会自动保存并恢复状态。

请记住在这种情况下,只有View会被摧毁和重建,Fragment没有任何变化,所以它的成员是不变的,这一点与Activity不同!

public class MainFragment extends Fragment {
 
    // These variable still persist in this case
    private int someVarA;
    private String someVarB;
 
    ...
 
}

是的,你注意到了,只有View覆写那两个保存/还原状态的方法,我们不需要做任何事,所以说:

每一个在你的程序中使用的View一定都要覆写Saving/RestoreState方法!

public class CustomView extends View {
 
    ...
 
    @Override
    public Parcelable onSaveInstanceState() {
        Bundle bundle = new Bundle();
        // Save current View's state here
        return bundle;
    }
 
    @Override
    public void onRestoreInstanceState(Parcelable state) {
        super.onRestoreInstanceState(state);
        // Restore View's state here
    }
 
    ...
 
}

Android的基础View。例如EditText, TextView, Checkbox and etc都实现了这些方法,我们需要做的就是将android:freezeText设为true即可使用这些特性。

如果你决定使用一些第三方自定义的View,如果它们没有覆写那两个方法,你必须手动实现这两个方法。

//
// Assumes that SomeSmartButton is a 3rd Party view that
// View State Saving/Restoring are not implemented internally
//
public class SomeBetterSmartButton extends SomeSmartButton {
 
    ...
 
    @Override
    public Parcelable onSaveInstanceState() {
        Bundle bundle = new Bundle();
        // Save current View's state here
        return bundle;
    }
 
    @Override
    public void onRestoreInstanceState(Parcelable state) {
        super.onRestoreInstanceState(state);
        // Restore View's state here
    }
 
    ...
 
}

如果你在写自定义ViewViewgroup,同样不要忘记覆写这两个方法,它真的很重要。

同样不要忘记为你的View赋予idandroid:id),如果没有idAndroid不会保存这些View的状态!


 

 

要清楚Fragment状态与View状态是不同的概念

为了确保你的code是整洁的,可扩展的,你必须吧FragmentView 状态分开。如果一个属性是属于View的,那么请把它的保存恢复工作放到View的saving/restoringstate 方法中,反之亦然。看一下示例:

public class MainFragment extends Fragment {
 
    ...
 
    private String dataGotFromServer;
     
    @Override
    public void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        outState.putString("dataGotFromServer", dataGotFromServer);
    }
 
    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        dataGotFromServer = savedInstanceState.getString("dataGotFromServer");
    }
 
    ...
 
}







你可能感兴趣的:(Android基础知识)