关于FragmentTransaction的各种提交方法: commit(),commitAllowingStateLoss(),commitNow()commitNowAllowingStateLoss().
作者Bryan Herbst发了一个blog The many flavors of commit()讨论这几个方法的特点和用途.
下文是中文摘要.

FragmentTransaction的提交方法

support library的FragmentTransaction现在提供了四种不同的方法来commit一个transaction:
commit()
commitAllowingStateLoss()
commitNow()
commitNowAllowingStateLoss()

这篇文章分析了这四个方法的不同.

commit() vs commitAllowingStateLoss()

commit()提交有时候会遇到IllegalStateException, 说你在onSaveInstanceState()之后提交, 这里有另一个文章很好地分析了这个问题:Fragment Transactions & Activity State Loss
commit()commitAllowingStateLoss()在实现上唯一的不同就是当你调用commit()的时候, FragmentManger会检查是否已经存储了它自己的状态, 如果已经存了, 就抛出IllegalStateException.
那么如果你调用的是commitAllowingStateLoss(), 并且是在onSaveInstanceState()之后, 你可能会丢失掉什么状态呢?
答案是你可能会丢掉FragmentManager的状态, 即save之后任何被添加或被移除的Fragments.
举例说明:
1.在Activity里显示一个FragmentA;
2.然后Activity被后台, onStop()onSaveInstanceState()被调用;
3.在某个事件触发下, 你用FragmentB replace FragmentA , 使用的是 commitAllowingStateLoss().
这时候, 用户再返回应用, 可能会有两种情况发生:
1.如果系统杀死了你的activity, 你的activity将会重建, 使用了上述步骤2保存的状态, 所以A会显示, B不会显示;
2.如果系统没有杀死你的activity, 它会被提到前台, FragmentB就会显示出来, 到下次Activity stop的时候, 这个包含了B的状态就会被存下来.
(上述测试可以利用开发者选项中的”Don’t Keep Activities”选项).
那么你要选择哪一种呢? 这就取决于你提交的是什么, 还有你是否能接受丢失.

commit(), commitNow() 和 executePendingTransactions()

使用commit()的时候, 一旦调用, 这个commit并不是立即执行的, 它会被发送到主线程的任务队列当中去, 当主线程准备好执行它的时候执行.
popBackStack()的工作也是这样, 发送到主线程任务队列中去. 也即说它们都是异步的.

但是有时候你希望你的操作是立即执行的, 之前的开发者会在commit()调用之后加上 executePendingTransactions()来保证立即执行, 即变异步为同步.
support library从v24.0.0开始提供了 commitNow()方法, 之前用executePendingTransactions()会将所有pending在队列中还有你新提交的transactions都执行了, 而commitNow()将只会执行你当前要提交的transaction. 所以commitNow()避免你会不小心执行了那些你可能并不想执行的transactions.

但是你不能对要加在back stack中的transaction使用commitNow(), 即addToBackStack()commitNow()不能同时使用.
为什么呢?
想想一下, 如果你有一个提交使用了commit(), 紧接着又有另一个提交使用了commitNow(), 两个都想加入back stack, 那back stack会变成什么样呢? 到底是哪个transaction在上, 哪个在下? 答案将是一种不确定的状态, 因为系统并没有提供任何保证来确保顺序, 所以系统决定干脆不支持这个操作.

前面提过popBackStack()是异步的, 所以它同样也有一个同步的兄弟popBackStackImmediate().

所以实际应用的时候怎么选择呢?

  1. 如果你需要同步的操作, 并且你不需要加到back stack里, 使用commitNow().
    support library在FragmentPagerAdapter里就使用了commitNow()来保证在更新结束的时候, 正确的页面被加上或移除.
  2. 如果你操作很多transactions, 并且不需要同步, 或者你需要把transactions加在back stack里, 那就使用commit().
  3. 如果你希望在某一个指定的点, 确保所有的transactions都被执行, 那么使用executePendingTransactions().

Reference

这是Android Weekly #220的一篇文章, 我在做这期笔记的时候觉得这个写得很好, 所以决定单独拿出来说一说. 这期整体的笔记稍后推出, 敬请期待哇.
原文The many flavors of commit()

commit(), commitNow()和commitAllowingStateLoss()的更多相关文章

  1. 【从零开始撸一个App】Fragment和导航中的使用

    Fragment简介 Fragment自从Android 3.0引入开始,它所承担的角色就是显而易见的.它之于Activity就如html片段之于页面,好处无需赘述. Fragment的生命周期和Ac ...

  2. FragmentTransaction的commit和commitAllowingStateLoss的差别

    1.什么是FragmentTransaction? 使用Fragment时.能够通过用户交互来运行一些动作.比方添加.移除.替换等. 全部这些改变构成一个集合,这个集合被叫做一个transaction ...

  3. Android Weekly Notes Issue #220

    Android Weekly Issue #220 August 28th, 2016 Android Weekly Issue #220 ARTICLES & TUTORIALS Manag ...

  4. 选择正确的 Fragment#commitXXX() 函数

    转自: http://www.tuicool.com/articles/q6R7nii 最新版本(v24.0.0)的 Support v4 库中的 FragmentTransaction 添加了 co ...

  5. Fragment Transactions和Activity状态丢失

    本文由 伯乐在线 - 独孤昊天 翻译.未经许可,禁止转载!英文出处:androiddesignpatterns.欢迎加入翻译组. 下面的堆栈跟踪和异常代码,自从Honeycomb的初始发行版本就一直使 ...

  6. 行政区划sql数据脚本

    行政区划sql数据脚本 IF (EXISTS(SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[TB_Province]') ...

  7. Fragment回退栈&commit()和commitAllowingStateLoss()

    Activity切换时是通过栈的形式,不断压栈出栈,在Fragment的时候,如果你不是手动开启回退栈,它是直接销毁再重建,但如果将Fragment任务添加到回退栈,情况就会不一样了,它就有了类似Ac ...

  8. 从源码看commit和commitAllowingStateLoss方法区别

    Fragment介绍 在很久以前,也就是我刚开始写Android时(大约在2012年的冬天--),那时候如果要实现像下面微信一样的Tab切换页面,需要继承TabActivity,然后使用TabHost ...

  9. Android_Fragment栈操作 commit()问题分析

    栈操作时遇到一个问题 getFragmentManager().beginTransaction() .replace(R.id.fl_container,bFragment) .addToBackS ...

随机推荐

  1. linux常用命令(1)cd命令

    1 命令格式:cd [目录名]2 命令功能切换当前目录至dirName3 常用范例3.1 进入系统根目录cd /3.2 进入上级目录cd ..   或者 cd ..//3.3 进入当前用户主目录当前用 ...

  2. swift 可选类型(optional)--- swift 入门

    一.思维导图 二.代码 //这样无形中就会让代码很丑陋 if x != nil && y != nil { print("x或y都不等于空") } print(&q ...

  3. MzBlog分析

    早上衣明志 在QQ群里说他的博客开源了,地址在 https://github.com/qihangnet/MZBlog,基于NancyFX和MongoDB开发的.博客内容需要使用 MarkDown 进 ...

  4. Spring8:一些常用的Spring Bean扩展接口

    前言 Spring是一款非常强大的框架,可以说是几乎所有的企业级Java项目使用了Spring,而Bean又是Spring框架的核心. Spring框架运用了非常多的设计模式,从整体上看,它的设计严格 ...

  5. DevExpress学习系列(控件篇):GridControl的基本应用

    一般属性设置 不显示分组框:Gridview->Option View->Show Group Panel=false 单元格不可编辑:gridcontrol -->gridview ...

  6. 海量数据处理利器greenplum——初识

    简介及适用场景 如果想在数据仓库中快速查询结果,可以使用greenplum. Greenplum数据库也简称GPDB.它拥有丰富的特性: 第一,完善的标准支持:GPDB完全支持ANSI SQL 200 ...

  7. APUE fig 1.10示例代码的完善--对提示符及输入回车的优化

    APUE 第3版第15页的shell2.c示例程序,运行效果如下: gcc ol.shell.c -o origin_shell ./origin_shell % date 2015年12月13日 星 ...

  8. Atitit 知识管理的重要方法 数据来源,聚合,分类,备份,发布 搜索

    Atitit 知识管理的重要方法 数据来源,聚合,分类,备份,发布 搜索 1.1. Rss 简易信息聚合(也叫聚合内容 Really Simple Syndication1 1.1. Rss 简易信息 ...

  9. 深入浅出Java三大框架SSH与MVC的设计模式

    现在许许多多的初学者和程序员,都在趋之若鹜地学习Web开发的宝典级框架:Struts2,Spring,Hibernate.似乎这些框架成为了一个人是否精通Java,是否会写J2EE程序的唯一事实标准和 ...

  10. JavaScript随笔5

    事件(1) 鼠标的点击坐标: 火狐不支持 IE event.clientX//可视区坐标 event.clientY FF ev.clientX ev.clientY 兼容: var oEvent = ...