13

我有一个TabActivitywhich hosts 5x FragmentActivity。其中一些包含按钮或列表,它们在onClick()oronItemClick()中创建和推送新片段。

在大多数情况下,这工作正常,但如果事情有点反应迟钝,或者测试人员做了一些愚蠢的事情(按住按钮或列表项,使用不同的手指切换选项卡,然后释放按钮/列表-- 100% 可重现),在活动暂停并保存后,我得到了点击事件。查看日志片段:

10-30 17:05:16.258  3415  3415 D BKC DEBUG: More.onSaveInstanceState()
10-30 17:05:16.258  3415  3415 D BKC DEBUG: MoreFragment.onPause()
10-30 17:05:17.309  3415  3415 D BKC DEBUG: MoreFragment.onItemClick()

在阅读了这篇文章和有关片段状态丢失的各种 StackOverflow 问题后,我没有看到如何解决这个问题的好答案。

  • 使用commitAllowingStateLoss()(无条件)是一种可以隐藏真正错误的解决方法。
  • 我不确定取消注册OnClickListeners 和OnItemClickListeners inonSaveInstanceState是否会 100% 阻止这种情况,对于每个片段中的每个按钮都这样做是一种 PITA。
  • 有人建议检查相关片段的isAdded(),但我可以确认这不起作用。
  • 我可以在 onClick() 中设置一个标志onSaveInstanceState()onRestoreInstanceState()检查它,但同样,这只是一个杂牌。编辑:哦,fragment 没有,但我可以在其中或其他任何onRestoreInstanceState()地方玩弄标志。onResume()

我是否缺少正确的解决方法,或者我应该选择我的kludge吗?

4

4 回答 4

4

再想一想,我相信这commitAllowingStateLoss()其实是本案的正确答案。我们知道我们在onClick()oronItemClick()处理程序中,所以如果可能发生状态丢失,我们知道是因为这个洞允许点击事件在onSaveInstanceState().

在我的随意测试中,当您返回相关选项卡时,实际上会弹出新片段,因为实际上没有任何内容被拆除。这对用户来说有点令人惊讶,但对于这种边缘情况来说可能是可以接受的。

于 2013-10-31T20:07:07.927 回答
2

我认为这里更优雅的解决方案是简单地忽略点击事件。在您的 BaseActivity 中设置一个非常简单的布尔标志来跟踪您的活动何时暂停:

class BaseActivity extends BaseFragmentActivity {
    private boolean isPaused;

    @Override
    protected void onPause() {
        isPaused = true;
        super.onPause();
    }

    @Override
    protected void onResume() {
        super.onResume();
        isPaused = false;
    }

    public boolean isPaused() {
        return isPaused;
    }
}

每当您收到点击事件时,只需检查您的活动是否已暂停。如果是,那么忽略该事件是非常安全的,因为对其采取行动是没有意义的。

@Override
public void onItemClick(AdapterView parent, View view, int position, long id) {
    if (isPaused()) {
        //But... we're paused. Ignore.
        return;
    }

    //Act upon legitimate click events here
}
于 2014-03-11T21:16:10.950 回答
2

I can confirm that this is a problem in the support library and not your code. The best workaround is (probably) to use the answer given by @Doge which is to track the paused state yourself.

The reason it's a problem with the support library is that onClicks happen after a click's release. If you're using multiple fingers, you can release another click event somewhere else (such as another button) which changes the fragment. The support library gets its click event after the fragment changes, and does not check to confirm it is still in the foreground. That means you have to check it yourself.

Which means that any call to setCurrentTab() or setCurrentTabByTag() must include a check for the paused state if they want to avoid this crash. Please correct me if I'm wrong.

于 2015-07-29T00:44:54.843 回答
1

由于 Activity 已暂停,并且确实没有对所选内容采取正确的操作,因此最好的操作可能是捕获并吃掉 IllegalStateException。让 UI 做它正在做的事情,让 FragmentTransaction 掉在地上。

于 2013-10-31T01:11:02.733 回答