【问题标题】:popBackStack in onPostExecute causes IllegalStateExceptiononPostExecute 中的 popBackStack 导致 IllegalStateException
【发布时间】:2017-05-10 00:49:07
【问题描述】:

抱歉,这是一篇比较长的帖子,让我先解释一下背景:

我已经阅读了很多关于这个主题的帖子(以及关于这个主题的Alex's excellent blog post),一般的结论似乎是不在异步回调中执行片段事务(参见Dianne's post),比如AsyncTask#onPostExecute() .

但是我有 2 种情况需要这样做:

  1. 一个Activity显示一个登录Fragment,当用户按下登录按钮时,一个AsyncTask开始与服务器进行身份验证,然后当返回登录成功时,登录Fragment被替换为主应用Fragment

  2. 显示主应用程序片段的Activity,当用户触发一些需要登录的操作时,登录片段替换添加到后台堆栈的主片段。再次按下登录按钮时,AsyncTask 与服务器进行身份验证,然后当登录成功时,我们想要弹出回栈以向用户显示主要的Fragment,并让他们执行他们想要执行的操作。

案例 1 可以使用 commitAllowingStateLoss 解决,但案例 2 很棘手,因为在 FragmentManager 中没有 popBackStack 的这种味道。

无论如何,这两种情况都需要在AsyncTask#doInBackground() 期间对应用程序进入后台进行特殊处理,从而导致onPostExecute() 在应用程序处于后台时被调用。一种解决方案是使用 Fragment.isResumed 来保护替换片段或弹出回栈,然后通过再次登录或保存一些指示最近成功登录的标志来处理进程终止情况,并在应用恢复状态下替换/弹出登录片段(登录@987654336 @ 由FragmentManager 恢复到顶部)。或者允许状态丢失,并处理进程被杀死然后恢复的情况,检查最近登录并删除登录片段。

你会这样处理吗?仅仅为了处理一个非常常见的情况,感觉就需要做很多工作。

【问题讨论】:

  • '感觉就像处理一个非常常见的情况需要做很多工作。'是的你是对的。我在一个应用程序中遇到了同样的问题。但作为替代方案,我建议您在活动中拆分主要片段和登录片段。这将简化处理此屏幕之间的转换。
  • 谢谢,有另一个登录活动可以为手机解决这个问题,但想象一下平板电脑 2 窗格布局(导航窗格和内容窗格),其中登录将内容窗格替换为片段,无法使用在这种情况下的活动:(

标签: android android-fragments android-activity illegalstateexception


【解决方案1】:

最近的解决方法是在popBackStack() 之前调用FragmentActivity.onStateNotSaved()

【讨论】:

【解决方案2】:

就像上面评论中提到的x90,最简单的解决方案是将您的片段拆分为单独的活动。这显然会避免异常,因为启动新活动不需要修改前一个活动的状态。像这样在屏幕上交换片段可能不是你想做的……正如他们的名字所暗示的那样,Fragments 被设计为用户界面的“片段”,而不是整个构成用户界面的屏幕。 (当然,我并不是说你不能允许以这种方式使用Fragments...我只是说这不是设计目标Fragment API)。

您也可以尝试在您的AsyncTask 中实施某种取消政策。也就是说,如果活动开始进入后台,请立即取消任务。当AsyncTask最终完成时,确保isCancelled()在执行片段事务等之前返回false

【讨论】:

  • 应用程序后台启动后(用户按下主页按钮或说电话打进来)是否会使我们的活动成为最重要的活动?我同意手机的多活动解决方案,但我认为平板电脑布局仍然需要片段,比如我们有一个带有导航和内容窗格的 2 窗格平板电脑布局,当前内容窗格需要用户登录,所以登录片段替换内容窗格(或添加到内容窗格的顶部)。在这种情况下,如果登录成功,我们希望关闭登录片段,而不是在登录片段中显示对话框或确认按钮
  • 继续上面的评论...我同意取消政策解决方案。因此,在异步回调成功的情况下,它需要通过保存实例状态机制(例如共享首选项或数据库)以外的某种方式持久保存这个事实,然后当应用程序处于前台时,登录片段检查这个持久化标志以查看如果登录确实通过了,则相应地自行关闭。
  • 再想一想,其实async回调可以只在fragment中设置一个boolean flag字段,可以在fragment的onStart方法中查看,如果设置dismiss,否则正常。片段中的 Dismiss 调用由 isResumed 保护(在应用后台返回 false 之后)。
猜你喜欢
  • 2014-11-22
  • 2018-03-30
  • 2014-06-19
  • 1970-01-01
  • 2017-03-15
  • 2014-08-02
  • 2015-04-20
  • 2012-05-09
  • 2014-10-07
相关资源
最近更新 更多