2014-01-21 152 views
2

在我的应用我想实现以下逻辑之一:删除片段)

1)在活动的在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例外

显然我失去了一些东西基本在活动< - >片段互动,那么处理我的用例的正确方法是什么?

+0

我不是100%确定这个。但我认为'onSaveInstanceState()'与'onStop()'方法相关联。那么也许你可以把当前在'onStop()'中的代码放入'onPause()'中? – Dreagen

+0

@Dreagen'onSaveInstanceState()'将在'onStop()'之前调用(如果完全调用它 - 如果Activity正在完成,则不会保存状态)。但是,在Android 3.0之前,它可能会在'onPause()'之前被调用。 – kcoppock

+2

尽管它没有提供针对您的特定情况的解决方案,但[this](http://www.androiddesignpatterns。com/2013/08/fragment-transaction-commit-state-loss.html)是一个非常好的资源,它是关于响应不直接附加到活动生命周期的异步进程执行片段事务的问题。 – kcoppock

回答

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

谢谢!请添加一个链接到您发布在评论中的文章,这启发了我重新设计我的设计:)。绝对可以对别人有用 –

+0

完成:)很高兴它帮助你。我有很多这方面的经验 - 我最终创建了一个无头碎片,它被添加到活动中并保留其状态,然后通过处理程序将消息发送回事件。当活动状态被保存时,我将片段置于分离状态(它将消息传递排队),然后当活动恢复时,我清除该标志,然后按顺序传递消息。 – kcoppock

2

解释这种异常的原因:

我看着奇巧源,它似乎popBackStack执行使用处理器及其工作(入列的动作):

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

所以它会执行在当前事件的整个生命周期之后。您可以尝试使用popBackStackImmediate,但它也会执行checkStateLoss();如果使用popBackStackImmediate,它也会执行checkStateLoss()。在非常begining

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

和checkStateLoss()检查变量mStateSaved其被设置为true的onSaveInstanceState中(但无法找到这种源的部分)。

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

+0

用于检出来源的投票,但不幸的是真正的问题是活动图像在调用onStop时已经保存。在onSaveInstanceState()期间,由Activity调用saveAllState()方法调用时,mStateSaved被设置为true。请参阅[活动来源](https://android.googlesource.com/platform/frameworks/base/+/refs/heads/master/core/java/android/app/Activity.java)。所以,如果我调用'popBackStackImmediate()'或者等到生命周期链完成,它并没有真正的区别 –