文章目录
本文记录笔者学习Fragment生命周期的心路历程
在这一部分中,我们单纯以Fragment为观察对象,观察其生命周期
在Android开发平台的官方文档中,对Fragment的生命周期有如下的描述
尽管 Fragment 的生命周期与其拥有的活动相关联,但它在标准活动生命周期上也有自己的缺陷。它包括基本的活动生命周期方法,例如onResume(),但与活动交互和 UI 生成相关的方法也很重要。
Fragment(与用户交互)的一系列核心生命周期方法是:
当一个Fragment不再被使用时,它会经历一系列反向回调:
放一张目前网上能找到的相对完整的生命周期如下
(相对完整),因为看过Google最新关于Fragment生命周期描述的uu就应该知道这篇生命周期的描述是不完整的,但是大体思路可以看看

这里给出如下案例进行阐述
onAttach() -------> onCreate() [Fragment]-------> onCreateView() ------>onCreate()[Activity]->onActivityCreated->onViewCreated() -----> onStart()-------> onStart()(Activity) -------->onResume()(Activity) --------> onResume()

onPause[Activity]->onPause[Fragment]->onStop[Activity]->onStop[Fragment]->onDestroy[Activity]->onDestroyView[Fragment]->onDestroy[Fragment]->onDetach[Fragment]

我们一般使用Fragment的无参构造函数,尽管我们可以通过自己定义书写Fragment的有参构造函数,但是这样做很容易导致不可预见的bug
当Activity被强制销毁,之后又被自动恢复的时候,Android系统会在这一过程中销毁并重新创建Fragment。
重新创建的机制是通过使用反射的方法来调用Fragment的无参构造函数来实现的。
因此,如果您是使用带参数的构造函数来实例化Fragment,并在其中将依赖的对象传递给它,那么在保存和恢复后,所有这些依赖的对象都将被设置为null。
因此,就像Activity一样,您需要使用onCreate(Bundle)方法作为构造函数的替代者。
Fragment中依赖对象的注入和初始化就发生在这里。
Fragment相关逻辑源码如下:
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getInjector().inject(this); // inject dependencies
if (savedInstanceState != null) {
mWelcomeDialogHasAlreadyBeenShown = savedInstanceState.getBoolean(SAVED_STATE_WELCOME_DIALOG_SHOWN);
}
mActivityAsListener = (ActivityAsListener) requireActivity();
}
看到这个方法,大多数人都会有疑惑的地方就是,为何Fragment不像Activity那样在onCreate()方法中初始化View呢,这里引用另外一位博主的解释
Activity在生命周期的转换过程中都只有同一个View hierarchy。 你在Activity的onCreate(Bundle)中初始化这个View hierarchy,然后它就会一直存在于Activity的整个生命周期,直到Activity被垃圾收集器回收为止。 您可以手动更改Activity的View hierarchy的组成,Android系统是不会为您做任何事情的。
然而,Fragment在其生命周期中可以存在有多个View hierarchy,由Android系统决定何时进行替换。
换句话说,你可以在程序运行的时候动态改变Fragment的View hierarchy,现在你应该清楚为什么不能在Fragment的onCreate(Bundle)中操作View了吧。 onCreate(Bundle)方法在Fragment被Attach到Activity后仅被调用一次,它无法支持Fragment的View hierarchy的动态化。
每次需要创建新的View hierarchy的时候,Android系统都会调用onCreateView(LayoutInflater, ViewGroup, Bundle)方法。 您的工作是创建View hierarchy并将其初始化为正确的状态,然后将它作为该方法的返回值,之后它就会被Android系统接管。
重写这个方法的主要原则是:Fragment中所有持有与View hierarchy相关的对象的引用的成员变量,必须在View onCreateView(LayoutInflater,ViewGroup,Bundle)中进行初始化。 换句话说,如果Fragment的成员变量持有View或者相关对象的引用,请确保在此方法中初始化这些成员变量,这非常重要。
换句话说,onCreateView()存在的意义就是使得Fragment可以动态改变其View hierarchy
参照Activity的onStart()方法
参照Activity
参照Activity的onPause()方法
这个方法的处理逻辑同样与Activity的onStop()方法相同。其基本的处理逻辑如下所示:
相关源码如下
@Override
public void onStop() {
super.onStop();
mSomeView.setOnClickListener(null);
mFirstDependency.unregisterListener(this);
}
在这里需要完成两件事
1.取消Activity的相关注册
2.取消点击事件
之所以这样做,可以参照以下的解释
1:
如果在onPause()方法里调用mFirstDependency.unregisterListener(this),那么Activity将不会收到相关异步流程完成的通知。因此,它不能让用户感知到这一事件,从而完全违背了多窗口模式的设计初衷,这不是一种好的处理方式。
如果在onDestroy()方法里调用mFirstDependency.unregisterListener(this),这同样不是一种好的处理方式。
当应用被用户推到后台(例如,点击“home”按钮)时,Activity的onStop()将被调用,从而使得其返回到“已创建”状态,这个Activity可以在几天甚至几周的时间内保持这个状态。
如果这时候mFirstDependency产生了连续的事件流,那么在这几天甚至几周的时间里,Activity可以都处理这些事件,即使用户在这段时间内从未真正与它交互过。这将是对用户电池寿命的不负责任的浪费,而且在这种情况下,应用消耗的内存会逐渐增多,应用进程被OOM(Out
Of Memory)Killer杀死的可能性也会增大。
因此,在onPause()和onDestroy()里调用mFirstDependency.unregisterListener(this)都不是一种好的处理方式,您应该在onStop()中执行此操作。
2:
关于2的解释,主要是用户使用APP的连续性和解决Activity停止后事件仍然进行分发的结果
不需要覆盖重写这个方法,这个方法完全只是相关资源的回收
此方法用于保存一些临时的状态,在这个方法里你位移需要做的就是将你想保存的状态存入Bundle数据结构中:
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putBoolean(SAVED_STATE_WELCOME_DIALOG_SHOWN, mWelcomeDialogHasAlreadyBeenShown);
}
在这里,有个陷阱,如果你在这个方法执行完之后,提交Fragment事务,那么应用程序会抛出IllegalStateException异常而导致崩溃。
你需要知道的一点是onSaveInstanceState(Bundle)将在onStop()之前被调用。
好消息是,经过多年的努力,谷歌终于意识到了这个bug。 在新版本的Android中,==onStop()将在onSaveInstanceState(Bundle)==之前被调用。
以上就是Fragment生命周期的分享和整理
很好奇,就使用rubyonrails自动化单元测试而言,你们正在做什么?您是否创建了一个脚本来在cron中运行rake作业并将结果邮寄给您?git中的预提交Hook?只是手动调用?我完全理解测试,但想知道在错误发生之前捕获错误的最佳实践是什么。让我们理所当然地认为测试本身是完美无缺的,并且可以正常工作。下一步是什么以确保他们在正确的时间将可能有害的结果传达给您? 最佳答案 不确定您到底想听什么,但是有几个级别的自动代码库控制:在处理某项功能时,您可以使用类似autotest的内容获得关于哪些有效,哪些无效的即时反馈。要确保您的提
在控制台中反复尝试之后,我想到了这种方法,可以按发生日期对类似activerecord的(Mongoid)对象进行分组。我不确定这是完成此任务的最佳方法,但它确实有效。有没有人有更好的建议,或者这是一个很好的方法?#eventsisanarrayofactiverecord-likeobjectsthatincludeatimeattributeevents.map{|event|#converteventsarrayintoanarrayofhasheswiththedayofthemonthandtheevent{:number=>event.time.day,:event=>ev
我在开发的Rails3网站的一些搜索功能上遇到了一个小问题。我有一个简单的Post模型,如下所示:classPost我正在使用acts_as_taggable_on来更轻松地向我的帖子添加标签。当我有一个标记为“rails”的帖子并执行以下操作时,一切正常:@posts=Post.tagged_with("rails")问题是,我还想搜索帖子的标题。当我有一篇标题为“Helloworld”并标记为“rails”的帖子时,我希望能够通过搜索“hello”或“rails”来找到这篇帖子。因此,我希望标题列的LIKE语句与acts_as_taggable_on提供的tagged_with方法
我正在编写一个包含C扩展的gem。通常当我写一个gem时,我会遵循TDD的过程,我会写一个失败的规范,然后处理代码直到它通过,等等......在“ext/mygem/mygem.c”中我的C扩展和在gemspec的“扩展”中配置的有效extconf.rb,如何运行我的规范并仍然加载我的C扩展?当我更改C代码时,我需要采取哪些步骤来重新编译代码?这可能是个愚蠢的问题,但是从我的gem的开发源代码树中输入“bundleinstall”不会构建任何native扩展。当我手动运行rubyext/mygem/extconf.rb时,我确实得到了一个Makefile(在整个项目的根目录中),然后当
这是一道面试题,我没有答对,但还是很好奇怎么解。你有N个人的大家庭,分别是1,2,3,...,N岁。你想给你的大家庭拍张照片。所有的家庭成员都排成一排。“我是家里的friend,建议家庭成员安排如下:”1岁的家庭成员坐在这一排的最左边。每两个坐在一起的家庭成员的年龄相差不得超过2岁。输入:整数N,1≤N≤55。输出:摄影师可以拍摄的照片数量。示例->输入:4,输出:4符合条件的数组:[1,2,3,4][1,2,4,3][1,3,2,4][1,3,4,2]另一个例子:输入:5输出:6符合条件的数组:[1,2,3,4,5][1,2,3,5,4][1,2,4,3,5][1,2,4,5,3][
我已经构建了一些serverspec代码来在多个主机上运行一组测试。问题是当任何测试失败时,测试会在当前主机停止。即使测试失败,我也希望它继续在所有主机上运行。Rakefile:namespace:specdotask:all=>hosts.map{|h|'spec:'+h.split('.')[0]}hosts.eachdo|host|begindesc"Runserverspecto#{host}"RSpec::Core::RakeTask.new(host)do|t|ENV['TARGET_HOST']=hostt.pattern="spec/cfengine3/*_spec.r
我们的git存储库中目前有一个Gemfile。但是,有一个gem我只在我的环境中本地使用(我的团队不使用它)。为了使用它,我必须将它添加到我们的Gemfile中,但每次我checkout到我们的master/dev主分支时,由于与跟踪的gemfile冲突,我必须删除它。我想要的是类似Gemfile.local的东西,它将继承从Gemfile导入的gems,但也允许在那里导入新的gems以供使用只有我的机器。此文件将在.gitignore中被忽略。这可能吗? 最佳答案 设置BUNDLE_GEMFILE环境变量:BUNDLE_GEMFI
这似乎非常适得其反,因为太多的gem会在window上破裂。我一直在处理很多mysql和ruby-mysqlgem问题(gem本身发生段错误,一个名为UnixSocket的类显然在Windows机器上不能正常工作,等等)。我只是在浪费时间吗?我应该转向不同的脚本语言吗? 最佳答案 我在Windows上使用Ruby的经验很少,但是当我开始使用Ruby时,我是在Windows上,我的总体印象是它不是Windows原生系统。因此,在主要使用Windows多年之后,开始使用Ruby促使我切换回原来的系统Unix,这次是Linux。Rub
最近因为项目需要,需要将Android手机系统自带的某个系统软件反编译并更改里面某个资源,并重新打包,签名生成新的自定义的apk,下面我来介绍一下我的实现过程。APK修改,分为以下几步:反编译解包,修改,重打包,修改签名等步骤。安卓apk修改准备工作1.系统配置好JavaJDK环境变量2.需要root权限的手机(针对系统自带apk,其他软件免root)3.Auto-Sign签名工具4.apktool工具安卓apk修改开始反编译本文拿Android系统里面的Settings.apk做demo,具体如何将apk获取出来在此就不过多介绍了,直接进入主题:按键win+R输入cmd,打开命令窗口,并将路
很难说出这里要问什么。这个问题模棱两可、含糊不清、不完整、过于宽泛或夸夸其谈,无法以目前的形式得到合理的回答。如需帮助澄清此问题以便重新打开,visitthehelpcenter.关闭9年前。我需要从基于ruby的应用程序使用AmazonSimpleNotificationService,但不知道从哪里开始。您对从哪里开始有什么建议吗?