道歉这是一篇相当长的帖子,让我先试着解释一下背景:
我已经阅读了很多关于这个主题的帖子(以及关于这个主题的Alex's excellent blog post),一般的结论似乎不是在异步回调中执行片段事务(参见Dianne's post),比如AsyncTask#onPostExecute()
。
但是我有2例需要这样做:
Activity
显示登录Fragment
,当用户按下登录按钮时,AsyncTask
开始向服务器进行身份验证,然后返回登录成功时,登录{ {1}}已替换为主应用Fragment
。
显示主应用程序片段的Fragment
,当用户触发需要登录的某个操作时,登录片段将替换添加到backstack的主片段。再次按下登录按钮时,Activity
将对服务器进行身份验证,然后当登录成功时,我们要弹出backstack以向用户显示主AsyncTask
并让他们执行他们想要执行的操作。
案例1可以使用Fragment
来解决,但案例2很棘手,因为commitAllowingStateLoss
中没有这种popBackStack的风格。
在任何情况下,这两种情况都需要特殊处理应用程序在FragmentManager
期间转到后台,导致在应用程序处于后台时调用AsyncTask#doInBackground()
。一种解决方案是使用Fragment.isResumed来保护替换片段或pop backstack,然后通过再次登录来处理进程被杀死的情况,或者保存一些标志,指示最近成功登录并在应用程序恢复状态下替换/弹出登录片段(login {{ 1}}由onPostExecute()
恢复到顶部。或者允许状态丢失,并处理进程终止然后恢复的情况,检查最近的登录并删除登录片段。
这是你怎么处理的?感觉就像处理一种非常常见的情况一样。
答案 0 :(得分:5)
最近的解决方法是在FragmentActivity.onStateNotSaved()
之前致电popBackStack()
。
答案 1 :(得分:1)
与上面评论中提到的x90一样,最简单的解决方案是将您的片段拆分为单独的活动。这显然会避免异常,因为启动新活动不需要修改先前活动的状态。像这样在屏幕内外交换片段可能不是你想要做的......正如他们的名字所暗示的,Fragment
s被设计成用作用户界面的“片段”,而不是那么多作为构成用户界面的整个屏幕。 (当然,我并不是说你不是允许以这种方式使用Fragment
...我只是说这不是一个设计Fragment
API的目标。
您还可以尝试在AsyncTask
中实施某种取消政策。也就是说,如果活动开始进入后台,请立即取消任务。当AsyncTask
最终完成时,请确保isCancelled()
在执行片段事务之前返回false
等。