转载请标明出处:
http://blog.csdn.net/yujun411522/article/details/45950111
本文出自:【yujun411522的博客】
1.Activity 生命周期
废话少说,上图:
图 官网上的Activity的生命周期图
Activity的生命周期非常重要,在不同的阶段做什么操作影响到用户体验。用户离开和再次进入时做的操作不一样。比如一个在线网络视频播放,activity处于pause状态时可以暂停播放、关闭网络(节省资源),用户返回时Activity处于resume状态时再重新打开网络,继续播放。
1.2 三个重要的状态(可以暂时停留的状态)
resumed:可见且拥有用户焦点可以和用户交互的状态,也称为Running状态。这种状态就是正常状态
paused:可见但是没有用户焦点不能交互。比如:A启动一个对话框,是否是透明的,这个时候A可见,但是不能和用户进行交互。
stoped:完全不可见。比如:A启动B,这是A变成stoped状态。再比如A点击Home键(Home其实也是一个app)。
1.3 生命周期回调函数
1.3.1 public voidonCreate(Bundle savedInstanceState),当Activity正要被创建时调用。做一些全局操作,如加载layout文件、加载数据绑定到listview。在onDestory中释放资源。关于savedInstanceState后面有详细介绍。killable:no
1.3.2 protected voidonStart(),当activity正要对用户可见时,这是一个瞬间状态,用于过渡。可以注册BroadCastReceiver,killable:no
1.3.3 protected voidonResume(),这一阶段就是可见且用户可以进行交互。做的操作不要过于耗时,否则影响用户体验。通常和onpause方法做的事情相反:注册监听,sensor,加载进度等。killable:no
1.3.4 protected voidonPause(),可见但是失去焦点,不能交互,如弹出一个对话框,这时可见但是不能与其交互。通常意味着进入pause状态。这通常在onPause函数中操作有:停止消耗cpu的动画、保存没有提交的数据、释放资源(broadcast receiver,sensor等耗时耗资源的操作)killable:yes
1.3.5 protected voidonStop(),完全不可见,进入后台运行。通常在onpause方法之前执行。可以在方法中做一些耗时操作,比如写数据库,保存持久化数据等。killable:yes
1.3.6 protected voidonDestory(),需要被摧毁时。大部分情况下在onpause和onstop方法之后执行,除非一种情况:onCreate中调用finish(不是onDestory)方法,这时系统直接调用destroy,不在调用其他生命周期方法。killable:yes
,如果oncreate中调用的是ondestory,结果则是
2.3.7protected void onRestart(),处于stop状态之后再次返回时,先调用onRestart,再调用onStart,killable:no
注意,在override这些方法时,一定要先调用父类的该方法,Activity相应的生命周期方法中做了很多重要的工作,不像service一样是空实现。
killable:在该方法返回之后系统能否将该activity所在的process杀死,而且不再执行activity其他的代码。由于onPause、onStop、onDestory都是killable。一旦activity被创建之后,onPause方法是最后一个保证在process被kill之前调用的方法。所以在onPause中保存一些持久化的数据(用户输入),但是不能太耗时,因为有可能是跳到另一个activity时调用onPause方法,这样的话启动另一个activity后慢一些,影响用户体验。
2 运行时状态(官网)
2.1保存运行状态
1.首先要明确的一点就是:当处于paused、stoped状态时,该activity对象还是在内存中,保存所有的状态和成员变量信息。所以当从后台状态返回到前台状态时,之前的activity中的信息还存在。比如文本框内容,checkbox选中的状态。这是正常状态。
2.上面也说过,当系统要回收资源时,可能将处于paused、stoped状态的activity杀死。对于用户来说是不清楚有这个过程的,所以当用户再次回到该activity时,希望看到的是和上次离开时一样的状态(比如文本框内容),这个过程对用户来说是透明的,也就是用户没有感觉到Activity被杀死然后重启。这个时候仅仅是重新create一个activity实例是不够的,还要加载上次Activity被杀死时的状态。android是通过onSaveInstanceState和onRestoreInstanceState来实现。这是不正常状态。
图 一个Activity从stop状态如何恢复到resume状态
3.当activity容易被杀死时,系统自动调用onSaveInstanceState。通过Bundle来存储状态信息。该方法默认的实现方式是调用该layout中所有的view的onSaveInstanceState方法,android中几乎所有的控件都能保存其任何可见的变化(文本框保存内容,checkbox保存是否选中等)。前提是为该控件设置id属性。所以此方法默认是保存ui状态。我们在实现时可以在bundle中保存数据(key-value)。要记住调用父类的onSaveInstanceState方法。
4.保存完activity的状态信息之后,接下来就是恢复:有两种方式,第一种是oncreate方法中,第二种是onRestoreInstanceState。如果使用oncreate方法,要进行判断是create一个activity还是重新恢复activity(判断bundle是否为空即可)。如:
<span style="font-size:14px;">public void onCreate(Bundle savedInstanceState){
if(savedInstanceState==null){
//说明是create一个实例
}else{
//恢复实例
int value=savedInstanceState.getInt(key);
}
}</span>
而onRestoreInstanceState则就是用来恢复状态信息的。要记得调用父类的此方法,然后在将之前保存的键值对取出来。如:
<span style="font-size:14px;">public void onRestoreInstanceState(Bundle savedInstanceState){
super.onRestoreInstanceState();
int value=savedInstanceState.getInt(key);
}</span>
4.要注意,onSaveInstanceState不一定保证该activity在destroy之前一定会调用。因为如果用户直接点击back键,就表明用户要离开界面,不需要保存信息。而且onSaveInstanceState在onStop方法之前,可能在onPause之前(也可能是之后,我测过好几次都在onPause之后)。
2.2 处理运行时配置改变
2.1中所说的在系统回收内存资源时有可能将处于pause或者stop状态的activity杀死,更加常见的是如用户旋转屏幕时activity的重新启动,也叫做运行时变化(Runtime Change)。当发生Runtime Change时系统重启该activity,目的是为了重新适应新的配置(屏幕旋转,语言等)。所以2.1中所说的保存activity状态很重要,因为Runtime Change经常发生(旋转屏幕)。2.1中保存的状态还不算麻烦,如果试想每次都要保存很大的数据比如bitmap(Bundle也不适合存放这种数据、占用大量内存空间),这时就不能仅仅依靠onSaveInstance方法了。可以考虑使用Fragment。这个Fragment可以保存数据,在重启activity之后可以将Fragment数据取出来(推荐使用),过程如下:
1.实现一个自己的Fragment
2.oncreate方法中设置setRetainInstance(true)
3.将Fragment加入到activity中
4.在Fragment中取数据
(详细代码请查看官网 http://developer.android.com/guide/topics/resources/runtime-changes.html#RetainingAnObject)
既然默认情况是重新实例化该activity,那么也有另一种处理方式:自己处理configuration变化(一般不推荐使用,因为这样系统无法将新的配置适配到此activity中,只有当真的要避免因为Runtime Change而引起重启时才这么做)。使用方式是在activity的configChanges标签中注明哪些Change由自己处理。当注明的这些change发生时,activity不会重启,而是调用activity的onConfigurationChanged方法。注意:如果出现了哪怕一个在configChanges没有注册过的Runtime Change,也会重启,不再执行onConfigurationChanged方法。比如最常用的横竖屏切换。如果编译环境在level 13 以后则横竖屏切换时还会导致sreen size变化。所以android:configChanges="orientation|screenSize",这样才能避免重启。这样在旋转屏幕时就不再重启实例,而是触发onConfigurationChanged方法。
上面也是说过,不推荐这么使用。为什么?这么处理change的一个目的是害怕需要保存activity中状态以便activity重启回上次被杀死时的状态,但是带来的问题是新配置无法适配(绝大数情况下旋转屏幕是为了全屏、设置字体是为了让字体更大、更改语种是为了显示更改后的语言)。更严重的问题是不能保证onConfigurationChanged一定执行成功(如果出现android:configChanges之外的东西就回重启,不再调用onConfigurationChanged),这种情况很常见,除非将所有的RunTime change都包含进来;也不能保证该activity在被系统杀死。所以保存activity状态时必须要做好的。
2.3 和其他activity配合使用
A->B过程中生命周期方法执行顺序
可以看出A的onPause方法在B的onCreate方法之前,A的onStop方法在B的onResume方法之后。如果想在B中使用A的数据,要在onPause中保存,不要在onStop方法中保存,只有当B可以拥有用户焦点时A才处于onstop状态。
按住back键,从B返回到A:
只有当A拥有焦点之后B才会stop、destroy
2.4 ondestroy和finish
当用户按住back键时,默认操作就是调用finish方法。
finish:Call this when your activity is done and should be closed.可以理解为只是从栈顶移开、占用的资源并没有释放,还会调用onpause和onstop
ondestory:对activity进行清理工作、回收该activity所占用的空间,这是该activity最后一步。
当点击back按钮时: