在Activity的onStop()中删除片段

时间:2014-01-21 22:59:22

标签: android android-fragments android-activity

在我的一个应用程序中,我正在尝试实现以下逻辑:

1)在Activity的onStart()期间启动一些网络操作并添加进度片段:

@Override
protected void onStart() {
    super.onStart();
    refreshData();
}

private void refreshData() {
    if (!isInProgress)
    {
       showSpinner();
    }
    //Do boring network request
    .......
}

private void showSpinner() {
    getSupportFragmentManager().beginTransaction()
        .add(new ProgressFragment(), "").addToBackStack("")
        .commitAllowingStateLoss();
}

private void hideSpinner() {
   getSupportFragmentManager().popBackStack();
}

2)在onStop()期间 - 取消活动网络操作(如果有)并停止进度条(如果正在运行):

@Override
protected void onStop() {
    if (isInProgress) {
        //cancel network op
        ....
        hideSpinner();
    }
    super.onStop();
}

3)在onSaveInstanceState()期间保存一些UI状态:

@Override
protected void onSaveInstanceState(Bundle outState) {
    outState.putInt("tab", getActionBar().getSelectedNavigationIndex());
    super.onSaveInstanceState(outState);
}

所以,问题是在onSaveInstanceState()之前调用onStop(),所以当我尝试删除进度条时 - 我得到java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState异常

显然我在Activity< - > Fragment交互中遗漏了一些基本内容,那么处理我的用例的正确方法是什么?

2 个答案:

答案 0 :(得分:2)

总体建议是避免提交事务以响应异步事件。有关详细信息,请参阅this article。但是,有时它是不可避免的,您可以设置一些更复杂的状态检查和恢复。

对于您的特定情况(似乎您希望在活动不再可见时网络请求停止),您可以采取相应的措施:

public class SampleActivity extends FragmentActivity {
    private static final String PROGRESS_FRAGMENT = "progress_fragment";

    @Override
    protected void onStart() {
        super.onStart();
        refreshData();
    }

    private void refreshData() {
        if (!isInProgress) {
            isInProgress = true;
            showSpinner();
        }
    }

    private void cancelRefresh() {
        if (isInProgress) {
            isInProgress = false;
            //cancel request
            hideSpinner();
        }
    }

    private void showSpinner() {
        getSupportFragmentManager()
                .beginTransaction()
                .add(new ProgressFragment(), PROGRESS_FRAGMENT)
                .commit();
    }

    private void hideSpinner() {
        FragmentManager mgr = getSupportFragmentManager();
        Fragment spinner = mgr.findFragmentByTag(PROGRESS_FRAGMENT);
        if (spinner != null) {
            mgr.beginTransaction()
               .remove(spinner)
               .commit();
        }
    }

    @Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        cancelRefresh();
    }

    @Override
    protected void onStop() {
        super.onStop();
        cancelRefresh();
    }
}

由于您不知道将调用onSaveInstanceState(),因此您可以在onSaveInstanceState()onStop()上取消取消。使用标志设置和跟踪片段的标签,它只会执行一次,并且应该是安全的。

答案 1 :(得分:2)

解释此异常的原因:

我查看了KitKat源代码,看来popBackStack使用处理程序执行其工作(将其操作排入队列):

http://androidxref.com/4.4.2_r1/xref/frameworks/base/core/java/android/app/FragmentManager.java#499

所以它将在当前事件的整个生命周期之后执行。

您可以尝试使用popBackStackImmediate,但它也会执行checkStateLoss();在刚开始的时候

http://androidxref.com/4.4.2_r1/xref/frameworks/base/core/java/android/app/FragmentManager.java#508

和checkStateLoss()检查变量mStateSaved,该变量在onSaveInstanceState中设置为true(但无法找到此源部分)。

http://androidxref.com/4.4.2_r1/xref/frameworks/base/core/java/android/app/FragmentManager.java#1321