Android onPostExecute中的popBackStack导致IllegalStateException

Android onPostExecute中的popBackStack导致IllegalStateException,android,android-fragments,android-activity,illegalstateexception,Android,Android Fragments,Android Activity,Illegalstateexception,抱歉这是一篇相当长的帖子,让我先解释一下背景: 我已经阅读了很多关于这个主题(以及这个主题)的文章,一般的结论似乎不是在异步回调中执行片段事务(请参阅),比如AsyncTask\onpostsecute() 但是,我有两种情况需要这样做: 显示登录片段的活动,当用户按下登录按钮时,异步任务开始向服务器进行身份验证,然后当返回登录成功时,登录片段被主应用程序片段替换 显示主应用程序片段的活动,当用户触发某些需要登录的操作时,登录片段将替换添加到backstack的主片段。再次,当按下登录按钮时,A

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

我已经阅读了很多关于这个主题(以及这个主题)的文章,一般的结论似乎不是在异步回调中执行片段事务(请参阅),比如
AsyncTask\onpostsecute()

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

  • 显示登录
    片段的
    活动
    ,当用户按下登录按钮时,
    异步任务
    开始向服务器进行身份验证,然后当返回登录成功时,登录
    片段
    被主应用程序
    片段
    替换

  • 显示主应用程序片段的
    活动,当用户触发某些需要登录的操作时,登录片段将替换添加到backstack的主片段。再次,当按下登录按钮时,
    AsyncTask
    会与服务器进行身份验证,然后当登录成功时,我们希望弹出backbackback,向用户显示主
    片段
    ,并让他们执行想要执行的操作

  • 案例1可以通过使用
    commitAllowingStateLoss
    解决,但案例2很棘手,因为
    FragmentManager
    中没有类似的popBackStack

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

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

    就像上面的评论中提到的那样,最简单的解决方案是将您的片段分割成单独的活动。这显然可以避免异常,因为启动新活动不需要修改以前活动的状态。像这样在屏幕内外交换片段可能不是你想做的事情。。。顾名思义,
    Fragment
    s被设计成用户界面的“片段”,而不是组成用户界面的整个屏幕。(当然,我并不是说不允许您以这种方式使用
    Fragment
    s……我只是说这不是
    Fragment
    API的设计目标)


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

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

    “仅仅为了处理一个非常常见的情况,感觉需要做很多工作。”是的,你是对的。我在一个应用程序中遇到了同样的问题。但作为替代,我可以建议您在活动中拆分主片段和登录片段。这将简化处理此屏幕之间的转换。谢谢,让另一个登录活动可以解决手机的问题,但想象一下tablet 2窗格布局(导航窗格和内容窗格),其中登录将内容窗格替换为一个片段,在这种情况下不能使用活动:(在应用程序后台启动活动吗(用户按下主页按钮或说电话进来)让我们的活动成为最重要的活动?我同意手机的多活动解决方案,但我认为平板电脑布局仍然需要片段,比如说我们有一个带导航和内容窗格的双窗格平板电脑布局,而当前的内容窗格要求用户登录,因此登录片段取代了内容窗格(或添加到内容窗格顶部)。在这种情况下,如果登录成功,我们希望取消登录片段,而不是在登录片段中显示对话框或确认按钮。从上面的注释继续…我同意取消策略解决方案。因此,在异步回调成功的情况下,它需要以某种方式(而不是通过保存实例)保留此事实状态机制(如共享首选项或数据库),然后当应用程序前景化时,login fragment检查此持久化标志,以查看登录是否实际通过,并相应地解除其自身。仔细想想,实际上异步回调可以在片段中设置一个布尔标志字段,该字段可以在片段的onStart方法中进行检查,如果设置为Dislose,则为normal。Dislose片段中的调用由isResumed保护(在app background之后返回false)。有趣的API,看起来像是在API 23中引入的,但通常可通过支持库获得。Activity flavor的意图听起来像是一个回调。但支持库FragmentActivity flavor可由客户端代码调用,客户端代码将实际修改fragment manager状态保存标志,从而防止出现恐惧不合法状态例外;)