今天对于Activity的生命周期又有了一点深入的理解。做个总结吧。
一、正常情况下的生命周期
什么叫正常情况下的生命周期呢?也就是我们经常了解的一个活动的正常的生命流程。不用过度解释,
总结如下:
(1)onCreate()方法
活动第一次创建时被调用。
(2)onStart()
活动由不可见变为可见的时候调用
(3)onResume()
当活动准备开始与用户交互时会触发该方法,一般只会在需要执行以下的操作时才重写该事件:
l 开始动画
l 开始监听GPS更新
l 显示一些相关的提示和对话框
l 注册广播监听
(4)onPause()
系统准备去启动或者恢复另外一个活动的时候调用。或者当活动被切换到后台时将触发该方法,一般我们需要在该事件做如下的事情:
l 保存用户未提交的数据
l 关闭或清除引用的资源
l 注销广播
l 如果存在正在显示的提示或者对话框,则必须利用.Dismiss()进行清除。
(5)onStop()
当该活动完全不可见的时候被调用。一般会由以下原因触发:
l 当一个新的活动打开,并覆盖该活动时
l 一个已存在的活动切换到前台时
l 活动被销毁时
OnStop不是每次都会被执行,如果内存低下时,系统将不会执行该事件,而是直接关闭该应用,所以大家在OnPause事件中就要保存好所以的参数等等。而不能依赖该事件。
(6)onDestroy()
活动销毁之前被调用
(7)onRestart()
当活动由停止状态变为运行状态时被调用。即当用户通过Home按钮将该用户切换到后台,并在之后又打开该应用则会触发该事件。一般也很少重写该方法。
贴一张大家都知道的流程图吧,如下:
需要极其注意的是:在onPause中执行的操作不能太耗时!
二、异常情况下活动的生命周期
这个是重点要说的!什么是异常情况呢?不好说,比如因为资源相关的配置发生改变或者系统内存不足时,活动就
会被杀死。这就属于异常情况,总之一句话:活动被异常终止!最常见的就是下面的两种情况:
(1)横屏或者竖屏切换时。此时因为切换之间系统要对活动中的布局里面的图片进行更换(比如你可能会准备同样的两张
图片,不同像素宽高,分别对应于横屏或者竖屏的情况),此时就会导致在切换时,活动被瞬间杀死又被瞬间重建!
(2)因为系统内存不足,活动被回收时。
发生意外终止,系统做出的对策就是会将活动中的数据进行自动保存,然后再需要的时候再将活动创建出来恢复数据。
因此,对应的生命周期如下图:
也就是说在发生意外时,系统会自动调用onSaveInstanceState方法来保存数据,在需要的时候再会重新创建出这个活动,
然后自动调用onRestoreInstanceState方法来恢复数据。你可能会有疑问,一个活动中可能有一个TextView,还有一个按钮,
可能还有其他的,那么当活动意外终止,怎么来控制保存这些控件的数据呢?其实任何一个view都重写了onSaveInstanceState
和onRestoreInstanceState方法,你可以翻看源码,看看发生意外时,每一个view都会自动保存什么。这里不再多说。
上面列出的两种意外情况下的活动的生命周期是一样的,都是如上图所示。系统内存不足,不好模拟。但是横屏和竖屏
比较好模拟。下面我们通过一个实际例子,来看看是不是真的如上面所述的那样。
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
新建一个项目。修改其Manifest文件,加入横竖和竖屏切换的感应,如下:
<activity android:name=".MainActivity" android:label="@string/app_name" android:screenOrientation="sensor" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity>
上面只贴出了修改的那段代码,黄色部分就是加入的自动切换横屏和竖屏的功能。
下面再修改其MainActivity代码,如下:
1 public class MainActivity extends ActionBarActivity { 2 3 private static final String Tag = "MainActivity"; 4 5 @Override 6 protected void onCreate(Bundle savedInstanceState) { 7 super.onCreate(savedInstanceState); 8 setContentView(R.layout.activity_main); 9 10 if(savedInstanceState != null) 11 { 12 String t = savedInstanceState.getString("save_test"); 13 Log.e(Tag,t+" "+"onCreate"); 14 } 15 16 } 17 18 @Override 19 protected void onSaveInstanceState(Bundle outState) { 20 super.onSaveInstanceState(outState); 21 22 String t = "save me "; 23 Log.e(Tag,t+"onSaveInstanceState"); 24 outState.putString("save_test",t); 25 } 26 27 @Override 28 protected void onRestoreInstanceState(Bundle savedInstanceState) { 29 super.onRestoreInstanceState(savedInstanceState); 30 31 String t = savedInstanceState.getString("save_test"); 32 Log.e(Tag,t+" "+"onRestoreInstanceState"); 33 } 34 35 36 }
代码中重写了onSaveInstanceState和onResoreInstanceState方法,然后就在各个方法中打印标签。
下面运行一下程序,做如下的操作:
也就是控制手机,做了一个横竖和竖屏的切换。我们来看一下打印结果,如下:
通过打印结果,就会发现在横屏和竖屏切换时,确实是调用了保存数据和恢复数据的那些方法。而从再一次
调用了onCreate方法,就知道活动被重建了。
+++++++++++++++++++++++++++++++++++++++++++++++++++++++
接着上面的分析,有没有方法让在横竖和竖屏切换时,不要重新创建活动呢??当然是肯定的。
其实很简单,只要在Manifest文件中加入configChanges属性即可。也就是当检测到confiChanges指定
的属性发生改变时,也不会再去重新创建活动了。
下面我们就修改代码,来测试一下。首先修改Manifest中的代码,如下:
<activity android:name=".MainActivity" android:label="@string/app_name" android:screenOrientation="sensor" android:configChanges="orientation|screenSize"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity>
可以看到,添加了一句(即黄色部分),即检测到方向发生改变或者屏幕的size改变,也不去重新创建活动。
这针对的就是横屏和竖屏的切换。
然后修改MainActivity中的代码,如下:
1 public class MainActivity extends ActionBarActivity { 2 3 private static final String Tag = "MainActivity"; 4 5 @Override 6 protected void onCreate(Bundle savedInstanceState) { 7 super.onCreate(savedInstanceState); 8 setContentView(R.layout.activity_main); 9 10 if(savedInstanceState != null) 11 { 12 String t = savedInstanceState.getString("save_test"); 13 Log.e(Tag,t+" "+"onCreate"); 14 } 15 16 } 17 18 @Override 19 protected void onSaveInstanceState(Bundle outState) { 20 super.onSaveInstanceState(outState); 21 22 String t = "save me "; 23 Log.e(Tag,t+"onSaveInstanceState"); 24 outState.putString("save_test",t); 25 } 26 27 @Override 28 protected void onRestoreInstanceState(Bundle savedInstanceState) { 29 super.onRestoreInstanceState(savedInstanceState); 30 31 String t = savedInstanceState.getString("save_test"); 32 Log.e(Tag,t+" "+"onRestoreInstanceState"); 33 } 34 35 @Override 36 public void onConfigurationChanged(Configuration newConfig) { 37 super.onConfigurationChanged(newConfig); 38 Log.e(Tag,"onConfigurationChanged"); 39 } 40 }
黄色部分是我们新增加的代码。然后运行程序,依然做一个横屏竖屏的切换操作,打印结果如下:
我们这次只有onConfiguration这一个方法被调用。onSaveInstanceState方法和onRestoreInstanceState方法
都没有被调用,onCreate方法也没有,即没有再重新创建活动了。这提示我们,如果在横竖屏切换过程中,还想做一些
逻辑操作的话,可以放在onConfiguration方法中。
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
总结:(1)系统只在异常终止了Activity时,才会调用onSaveInstanceState和onRestoreInstanceState方法
来恢复数据。因此我们可以重写这两个方法来防止活动被出现意外终止时,数据发生丢失。
(2)如果使用了在Manifest文件中加入configChanges属性来监测发生变化时不再重新创建活动,那么
onConfiguration方法会被自动回调,我们可以在这里实现相关逻辑。
(3)就是上面的两张图,一个正常活动生命周期的图,一个异常下活动生命周期的图。