当前位置: 首页 > 编程日记 > 正文

Fragment提交transaction导致state loss异常

下面自从Honeycomb发布后,下面栈跟踪信息和异常信息已经困扰了StackOverFlow很久了。

java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState at android.support.v4.app.FragmentManagerImpl.checkStateLoss(FragmentManager.java:1341) at android.support.v4.app.FragmentManagerImpl.enqueueAction(FragmentManager.java:1352) at android.support.v4.app.BackStackRecord.commitInternal(BackStackRecord.java:595) at android.support.v4.app.BackStackRecord.commit(BackStackRecord.java:574)

这篇文章会解释这个异常什么时候会抛出以及原因,并且会以一些建议收尾。这些建议会帮助你不会因为这个异常导致程序崩溃。

这个异常为什么会抛出?

这个异常抛出的原因是因为你尝试着在Activity的状态已经保存后commit一个FragmentTransaction ,导致了一个现象叫做Activity state loss。在我们深入细节之前,让我们先看看在onSaveInstanceState()调用后发生了什么。在我的前一篇 Binders & Death Recipients有讨论到,Android应用程序在Android 运行时系统中只有很小的控制权。Android系统为了释放内存可以在任意时刻停止进程,然后处于后台的Activity就会被毫无警告地杀掉。为了保证有时候因此引起的不稳定行为能避免用户知道,Android框架给每一个Activity通过调用onSaveInstanceState()来保存自己状态的机会,它会在Activity可能被销毁之前调用。当后面恢复状态的时候,用户不会感觉到Activity已经被系统杀掉了,而会感觉前台和后台的Activity无缝切换。

当Android框架调用onSaveInstanceState(),它将一个Bundle对象通过这个方法传递,以便Activity后面恢复状态。Activity可以将它的Dialog、fragment以及view的状态保存在Bundle中。当这个方法返回的时候,系统通过Binder结果打包Bundle对象然后传给系统服务进程。系统服务进程负责保证Bundle对象安全地保存下来。当系统后面决定重新创建Activity的获释后,它就会将相同的Bundle对象发挥应用程序,以便于用它来回复旧的Activity状态。

所以为什么这个异常随后抛出?这个问题导致的原因是因为那些Bundle对象代表Activity在onSaveInstanceState()被调用那时候的一个快照,没更多了。这就意味着当你在onSaveInstanceState()之后调用FragmentTransaction#commit()的时候,transation不会被记录。因为它不会作为之前Activity的状态被保存。从用户的角度来说,这个transaction就像丢失了,导致UI状态意外的丢失。为了保证用户体验,Android不计一切代价避免状态丢失,也就是当它发生的时候简单地抛出一个IllegalStateException

这个异常什么时候会抛出?

如果你之前已经碰到过这个异常,你可能会注意到异常抛出的时机因为不同的Android版本而不一致。比如,如可能会发现老版本的设备上,这个异常抛出比较不频繁,或者当你的程序中使用support library而不是官方框架中的类时更容易触发这个异常。这些轻微的一致让很多人都以为support library有bug,不值得信任。然而,这些假设都不是正确的。

这些轻微的不一致是因为在Honeycomb版本中的Activity生命周期有了重要的变化。Honeycomb之前的版本,activity被认为在pause之前都不会被杀掉,这意味着onSaveInstanceState()会在onPause()之前被调用。从HoneyComb开始,Activity被认为只会在stopped只会被杀掉,意味着onSaveInstanceState()现在会在onStop()之前被调用而不是在onPause()之前。这些变化在下表中总结:

Honeycomb之前Honeycomb之后
Activity是否可以在onPause()之前被杀掉?NONO
Activity是否可以在onStop()之前被杀掉?YESNO
onSaveInstanceState(Bundle) 保证在...之前被调用onPause()onStop()

由于Activity生命周期的轻微变化,support library有时候需要根据系统版本选择他的行为。比如,在Honeycomb及以上设备,每次在onSaveInstanceState()之后调用commit()都会抛出一个异常,以便警告开发者已经发生了状态丢失。然而,在每次这种情况抛出异常在Honeycomb之前的设备上就显得太具有限制性了,它们的onSaveInstanceState()调用发生在Activity生命周期中更早的一段时期,并且更容易导致意外的状态丢失。Android团队被迫做出妥协:为了更好地跟老版本兼容,旧设备可能必须要忍受在onPause()onStop()之间意外的状态丢失。Support library在不同两个版本的行为如下表总结:

Honeycomb之前Honeycomb之后
commitonPause()之前OKOK
commitonPause()onStop()之间STATE LOSSOK
commitonStop()之后EXCEPTIONEXCEPTION

怎么避免这个异常?

一旦你懂得了真正发生了什么,避免Activity状态丢失就简单多了。如果你已经在读这篇文章之间就已经解决过这个问题了,希望你能对support library有一个更深的了解,并且知道为什么避免状态丢失对你的程序这么重要。为了方便你通过这篇文章寻找快速的解决方案,这里有一些建议希望你记得在使用FragmentTransactions的时候使用:

  • 在Activity生命周期方法中commit transation的时候一定要小心。很多应用程序只会在onCreate()或者为了响应用户输入的时候调用一次,所以他们不会遇到任何问题。然而,当你的transation开始冒险在其他的生命周期(比如onActivityResult()onStart()onResume() )中commit的时候,事情就可能变得棘手了。比如,你不应该在FragmentActivity#onResume() 方法中commit transation,为了避免有些时候这个方法在Activity的状态恢复之前被调用( 查看文档,了解更多)。如果你的应用程序需要在处理onCreate()之外的生命周期方法中commit transation,在FragmentActivity#onResume() 或者Activity#onPostResume()中调用。这两个方法会被保证在Activity恢复它的状态之后调用,因此会避免可能的状态丢失。(一个关于如何去做的例子,可以查看我在StackOverFlow上的回答。这个回答设计怎么正确地响应Activity#onActivityResult()方法,然后commit FragmentTransactions)

  • 避免是异步调用方法中执行transactions 。这个包括经常被使用的方法比如AsyncTask#onPostExecute()LoaderManager.LoaderCallbacks#onLoadFinished() 。在这些方法中执行transactions会有问题,因为他们当这些方法被回调的时候,他们不知道Activity当前的生命周期。比如,考虑下面的事件序列:

    1. 一个Activity执行一个AsyncTask
    2. 用户按下Home键,导致这个Activity的onSaveInstanceState()onStop() 方法被回调。
    3. AsyncTask完成然后onPostExecute()被调用,而不知道Activity已经处于stopped状态。
    4. onPostExectute()方法中的FragmentTransaction被committed,导致一个异常被抛出。

总之,在这些案例中避免异常抛出的最优方法就是避免在异步回调方法中commit transactions。Google工程师似乎同意这个见解。根据在Android Develop group上的这篇文章,Android开发团队认为通过commit FragmentTransactions来让UI产生重大的变化对用户体验十分不友好。如果你的应用程序需要在这些回调方法中执行transaction,那么没有什么简单方法可以保证这些回调不会再onSaveInstanceState()后调用,你可能必须使用commitAllowStateLoss()并且处理可能发生的状态丢失。(详见两篇StackOverFlow文章,文章1、文章2)

  • 只使用commitAllowingStateLoss()作为最后的解决方案commit()commitAllowingStateLoss()唯一的区别是后者在状态丢失的时候不会抛出异常。通常你不会想使用这个方法因为它意味着状态丢失可能发生。更好的解决方案当然是修改你的程序以便commit()被保证在activity的状态被保存前调用,因为这样可能会让用户体验更好。除非状态丢失是不可避免的,否则commitAllowingStateLoss()就不应该被使用。

希望这些建议能够帮助你解决以往因为这个异常而引起的问题。如果你还有问题,在StackOverflow上发布问题,然后将链接发表在评论区以便我能够看到。

译文链接Fragment transaction commit state loss

相关文章:

ASP网络编程从入门到精通 下载

《ASP网络编程从入门到精通》 清华大学出版社 特点: 面向ASP零基础读者,循序渐进 全面分析ASP技术细节 用代码描述个个知识点,操作性强 通过典型模块设计,体会ASP的奥妙 通过网上商城购物系统,增加项目开发经验 适合的…

项目Makefile文件模板

整理出来的一个Makefile模板,新增了一个内容,调用gcc生成依赖文件,这样如果某个c文件包含的头文件被更新了,该c文件以及依赖于该c文件的obj文件都会被重新编译.这个模板是按照我习惯的项目文件组织形式进行定义的,我的习惯是头文件放在include文件夹,代码放在src文件夹,目标文件…

小撒、金晨都想拥有!百度全球首款汽车机器人亮相,车内躺着看星星

整理 | 禾木木 出品 | AI科技大本营(ID:rgznai100) 金晨坐了都想带回家的车、无人车出行服务、撒贝宁与祝融号对话等等。 这届百度世界大会真的很惊艳。 8月18日,百度与央视新闻联合举办“AI这时代,星辰大海——百度世界大会2021…

解决oracle11g安装导致数据库无法自动搜集统计信息-转

近期发现个别11G数据库无法自动收集统计信息,部分视图查询结果如下: SQL> select client_name,status from dba_autotask_client where client_name auto optimizer stats collection;CLIENT_NAME STATUS -----------------------------------------…

服务器监控--cacti中英文版安装全解

近段时间一直在整服务器监控方面的东西,以下就是cacti中英文版安装的全过程,各安装包基本都是最新的,基于Centos 5.2平台下安装的!!#!/bin/bash# BY kerryhu# QQ:263205768# MAIL:king_819163.com# BLOG:[url]http://kerry.blog.51cto.com[/url]# Please manual operation yum …

lighttpd1.4.18代码分析

lighttpd1.4.18代码分析(八)--状态机(2)CON_STATE_READ状态posted 2008-09-24 10:50 那谁 阅读(2225) | 评论 (1) 编辑 lighttpd1.4.18代码分析(七)--状态机(1)CON_STATE_REQUEST_START状态posted 2008-09-22 15:10 那谁 阅读(2259) | 评论 (0) 编辑 lighttpd1.4.18代码分析…

惊艳亮相!马斯克发布自研超算 Dojo 芯片、特斯拉人形机器人

编译 | 禾木木 出品 | AI科技大本营(ID:rgznai100) 北京时间 8 月 20 日,特斯拉 AI 日终于开始了!在活动上不仅推出自研计算机系统Dojo 及 D1 芯片,同时还推出了特斯拉的下一个大型项目:人形机器人&#x…

git revert和git reset的区别

git revert 是撤销某次操作,此次操作之前的commit都会被保留git reset 是撤销某次提交,但是此次之后的修改都会被退回到暂存区具体一个例子,假设有三个commit, git st:commit3: add test3.ccommit2: add test2.ccommit1: add test…

python之深浅拷贝

对于 数字 和 字符串 而言,赋值、浅拷贝和深拷贝无意义,因为其永远指向同一个内存地址。 import copy # ######### 数字、字符串 #########n1 123 # n1 "age 10"print(id(n1)) # ## 赋值 ##n2 n1 print(id(n2)) # ## 浅拷贝 ##n2 copy.cop…

linux:关于Linux系统中 CPU Memory IO Network的性能监测

我们知道:系统优化是一项复杂、繁琐、长期的工作.通常监测的子系统有以下这些:CPUMemoryIONetwork下面是常用的监测工具Linux 系统包括很多子系统(包括刚刚介绍的CPU,Memory,IO,Network,等&…

火爆 GitHub!这个 AI 神器究竟有什么魅力?

图像分割(image segmentation)技术是计算机视觉领域的一个重要的研究方向,图像分割是计算机视觉中的一个关键过程。它包括将视觉输入分割成片段以简化图像分析。片段表示目标或目标的一部分,并由像素集或“超像素”组成。图像分割…

HTTP 状态代码

HTTP 状态代码 如果向您的服务器发出了某项请求要求显示您网站21kaiyun.com上的某个网页(例如,当用户通过浏览器访问您的网页时),那么,您的服务器会返回 HTTP 状态代码以响应该请求。 此状态代码提供了有关请求状态的信…

[Web 开发] 定制IE下载对话框的按钮(打开/保存)

下图常见的IE 下载对话框, 上面有3个主要按钮: Run (打开), Save(保存), Cancel (取消) 在某些情况下, 你不希望用户点击“Run” 按钮 或者 “Sav…

25 年汽车技术老兵亲述,自动驾驶新驶向

受访者 | 俞斌 记者 | 伍杏玲 出品 | AI科技大本营(ID:rgznai100) 在 IT 发展长河中,我们面对过不同的技术风口,历史终究大浪淘沙沉者为金。其中“自动驾驶”似乎是经久不衰的“风口”,成为人类的终极追求之一&#xf…

当你学了现在的忘了前面的

我怀疑我的智商应该不是很高,要不然我也不会学的如此狼狈。虽然我总是能很好的理解现在所学的知识点,但是我就是记不住,当下次再次需要上次的知识点来解决问题的时候,我总是忘的差不多了,要不就是没把握和对不对的问题…

HTTP referer

HTTP Referer是header的一部分,当浏览器向web服务器发送请求的时候,一般会带上Referer,告诉服务器我是从哪个页面链接过来的,服务器籍此可以获得一些信息用于处理。比如从我主页上链接到一个朋友那里,他的服务器就能够…

设置grep高亮显示匹配项

grep是个非常高频的命令,我们通过给它设置别名,来把匹配项区分出来,这样可以更直观。 设置前: 12[rootzabbix ~]# /sbin/ifconfig eth0 | grep inet addr inet addr:192.168.88.66 Bcast:192.168.88.255 Mask:255.255.255.0 设置…

PHP之源码目录结构

PHP之所以能在web开发语言中排名靠前,不仅仅是因为语法简单,上手容易。我个人认为更多是因为其语言本身的:模块的易扩展性,可维护性以及内存安全管理等特点。写过PHP的程序员不一定都知道:PHP是如何执行的?…

SSAS系列——【07】多维数据(查询Cube)

原文:SSAS系列——【07】多维数据(查询Cube)1、什么是MDX? MDX叫做“多维表达式”,是一种查询语言,是一种和SQL类似的查询语言,它基于 XML for Analysis (XMLA) 规范,并带有特定于 SQL Server A…

什么是图数据库?图数据库实践与创新浅析

近日,中国工程院院士,清华大学计算机科学与技术系教授郑纬民先生,在人民日报发表文章《把握图数据库自主创新机遇》,建议国内科研学者和工程人员,要在图数据库的理论研究与工程研发上坚持自主创新道路,确保…

C# 对应 Oracle 存储过程 的 SYS_REFCURSOR 应该 传入什么类型的参数?

Oracle中scott用户下创建存储过程:(注:从9i开始有了sys_refcursor这种类型,在以前的Oracle版本中需要使用REF CURSOR,并且还需放在一个程序包中)create or replace procedure sp_getdept(result out sys_refcursor)asbeginopen result for se…

Fedora 15 安装与配置一览

Fedora 15 将于2011.5.24日发布,今日离正式版发布还有4天。笨兔兔这里提前给大家支招用好Fedora 15。下面是笨兔兔在安装、配置Fedora 15 过程中的小结,希望给大家配置自己的Fedora 15 带来方便。仅供参考,如有错误,敬请指出。 『…

Win7封装无损廋身清单

整理了一下,大致如下。清理不会伤及系统功能。娱乐性的东西建议删除,因为这些不是功能性的,包括示例视频、示例音乐和一些主题图片以及一些系统自带的游戏。另外一些属于安装过程中产生的,重装封装不需要这些文件,对比…

苹果新算法已混进 iOS 14.3!CSAM 检测技术再遭网友争议

整理 | 禾木木、郑丽媛 出品 | AI科技大本营(ID:rgznai100) 苹果宣布即将推出 CSAM 检测系统时,遭到了 4000 多个组织及个人的公开反对,他们质疑苹果会破坏用户隐私和端到端加密机制。一位 Reddit 用户发现 CSAM 算法竟已被悄悄地…

2.最详细的WSDD配置文件注释

https://blog.csdn.net/u011063151/article/details/52590282转载于:https://www.cnblogs.com/sharpest/p/7851185.html

CloudStack部署篇二 高级网络设置

CloudStack 4.2.1版本基础安装: http://51log.blog.51cto.com/6076767/1598046测试默认UI访问 http:ip1:8080/client/选择【我以前使用过cloudstack,跳过配置指南】;开始应用网络配置;一、 高级网络部署管理服务器 (mangermant m…

阿里安全新研究:给图片打“马赛克”就能骗过 AI 视觉系统

阿里安全人工智能 AAIG 实验室等机构的研究者提出了一个新的机制来生成对抗样本,即与增加对抗扰动相反,他们通过扔掉一些不可察觉的图像细节来生成对抗样本。这项研究成果已被 AI 顶会 ICCV 2021 收录。 不久前,某知名品牌汽车被曝其自动驾驶…

Ubuntu下安装Apache+PHP+Mysql

Ubuntu下安装 apachephpmysql文本服务器! -------------------------------------------------------------------------------- 版本一 Install SSH Client and Server (for my remote access):sudo apt-get install ssh Install Database Server:sudo apt-…

2015香港书展

去年错过了书展,今年早早提醒自己不要错过。10点前我就到了会展中心,排队等待入场,依旧是那么多人,不过多数是年轻学生。在去的路上,没有看到13年那么多的反GCD或者反CY的宣传。 浦一进场,我便在门口张望了…

Firefox下http协议监测工具LiveHttpHeaders

当我们测试Web应用程序的安全性的时候,经常需要对HTTP流量进行分析和动态修改。此外,取得对Web 应用程序流出和流入的数据的控制权不仅对Web 应用程序安全缺陷的发现和漏洞的利用等安全测试任务具有很大的帮助,而且还有利于常规的Web 应用程序…