设为首页 加入收藏

TOP

Android Fragment使用(三) Activity, Fragment, WebView的状态保存和恢复(三)
2017-10-13 10:12:11 】 浏览:6474
Tags:Android Fragment 使用 Activity WebView 状态 保存 恢复
ragment == null) { tab1Fragment = new Tab1Fragment(); } tab2Fragment = getFragmentManager().findFragmentByTag(Tab2Fragment.TAG); if (tab2Fragment == null) { tab2Fragment = new Tab2Fragment(); } }

然后点击两个按钮来切换它们, replace(), 并且不加入到back stack中:

@OnClick(R.id.tab1)
void onTab1Clicked() {
    getFragmentManager().beginTransaction()
            .replace(R.id.content_container, tab1Fragment, Tab1Fragment.TAG)
            .commit();
}

@OnClick(R.id.tab2)
void onTab2Clicked() {
    getFragmentManager().beginTransaction()
            .replace(R.id.content_container, tab2Fragment, Tab2Fragment.TAG)
            .commit();

}

可以看到, 每一次的切换, 都是一个Fragment的完全destroy, detach和另一个fragment的attach, create,
但是当我在这两个fragment中各自加上EditText, 发现只要EditText有id, 切换过程中EditText的内容是被保存的.
这是谁在什么时候保存并恢复的呢?
我在TextChange的回调里打了断点, 发现调用栈如下:
Fragment restore view
FragmentManagerImpl中, moveToState()方法的case Fragment.CREATED中:
调用了: f.restoreViewState(f.mSavedFragmentState);
此时我没有做任何保存状态的处理, 但是断点中可以看出:
Fragment states
虽然mSavedFragmentState是null, 但是mSavedViewState却有值.
所以这个View状态保存和恢复对应的入口即是上面两个图中的入口三.

这是因为我的两个fragment只new了一次, 然后保存了成员变量, 即便是Fragment重新onCreate(), 但是对应的实例仍然是同一个.
这和Activity是不同的, 因为你是无法new一个Activity的.

在上面的例子中, 如果不保存Fragment的引用, 每次都new Fragment, 那么View的状态是不会被保存的, 因为不同实例间的状态传递只有在系统销毁恢复的情况下才会发生(入口一).
如果我们需要在不同的实例间传递状态, 就需要用到下面的方法.

不同Fragment实例间的状态保存和恢复

这里对应的是入口2, 不同于入口1和3, 它们是自动的, 入口2是用户主动保存和恢复的情形.
自己主动保存Fragment的状态, 可以调用FragmentManager的这个方法:

public abstract Fragment.SavedState saveFragmentInstanceState(Fragment f);

它的实现是这样的:

@Override
public Fragment.SavedState saveFragmentInstanceState(Fragment fragment) {
    if (fragment.mIndex < 0) {
        throwException(new IllegalStateException("Fragment " + fragment
                + " is not currently in the FragmentManager"));
    }
    if (fragment.mState > Fragment.INITIALIZING) {
        Bundle result = saveFragmentBasicState(fragment);
        return result != null ? new Fragment.SavedState(result) : null;
    }
    return null;
}

返回的数据类型是: Fragment.SavedState, 这个state可以通过Fragment的这个方法设置给自己:

public void setInitialSavedState(SavedState state) {
    if (mIndex >= 0) {
        throw new IllegalStateException("Fragment already active");
    }
    mSavedFragmentState = state != null && state.mState != null
            ? state.mState : null;
}

但是注意只能在Fragment被加入之前设置, 这是一个初始状态.
利用这两个方法可以更加自由地保存和恢复状态, 而不依赖于Activity.
这样处理以后, 不必保存Fragment的引用, 每次切换的时候虽然都new了新的实例, 但是旧的实例的状态可以设置给新实例.

例子代码:

@State
SparseArray<Fragment.SavedState> savedStateSparseArray = new SparseArray<>();

void onTab1Clicked() {
    // save current tab
    Fragment tab2Fragment = getSupportFragmentManager().findFragmentByTag(Tab2Fragment.TAG);
    if (tab2Fragment != null) {
        saveFragmentState(1, tab2Fragment);
    }

    // restore last state
    Tab1Fragment tab1Fragment = new Tab1Fragment();
    restoreFragmentState(0, tab1Fragment);

    // show new tab
    getSupportFragmentManager().beginTransaction()
            .replace(R.id.content_container, tab1Fragment, Tab1Fragment.TAG)
            .commit();
}

private void saveFragmentState(int index, Fragment fragment) {
    Fragment.SavedState savedState = getSupportFragmentManager().saveFragmentInstanceState(fragment);
    savedStateSparseArray.put(index, savedState);
}

private void restoreFragmentState(int index, Fragment fragment) {
    Fragment.SavedState savedState = savedStateSparseArray.
首页 上一页 1 2 3 4 5 下一页 尾页 3/5/5
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇Java 策略模式和状态模式 下一篇Android Fragment使用(三) Activi..

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目