温故而知新很重要,对于先前学过的东西,每一次回过头来看都有不一样的体会,要么理解更深了,要么理解更透彻了。
近来回顾了关于Activity的生命周期,参看了相关书籍和官方文档,有了不小的收获,在以前的认知上有了很大程度上的改善,在这里记录点东西。
先来看下经典生命周期图:
简单概要下:
1、当第一次调用一个Activity就会执行onCreate方法
2、当Activity处于可见状态的时候就会调用onStart方法
3、当Activity可以得到用户焦点的时候就会调用onResume方法
4、当Activity被遮挡住的时候就会调用onPause方法,遮挡结束会返回用户获取焦点状态的onResume方法
5、当Activity处于不可见状态的时候就会调用onStop方法,如果Activity没有被销毁会重新调用onRestart方法,然后返回onStart方法
7、当Activity被销毁时会调用onDestory方法
来段代码测试下:
1 package com.lcw.rabbit.activity; 2 3 import android.app.Activity; 4 import android.content.res.Configuration; 5 import android.os.Bundle; 6 import android.util.Log; 7 8 public class MainActivity extends Activity { 9 10 private String mInfo; 11 12 @Override 13 protected void onCreate(Bundle savedInstanceState) { 14 super.onCreate(savedInstanceState); 15 setContentView(R.layout.activity_main); 16 Log.i("Rabbit", "onCreate------"); 17 mInfo="I Am Rabbit"; 18 } 19 20 @Override 21 protected void onStart() { 22 super.onStart(); 23 Log.i("Rabbit", "onStart------"); 24 } 25 26 @Override 27 protected void onResume() { 28 super.onResume(); 29 Log.i("Rabbit", "onResume------"); 30 } 31 32 @Override 33 protected void onPause() { 34 super.onPause(); 35 Log.i("Rabbit", "onPause------"); 36 } 37 38 @Override 39 protected void onStop() { 40 super.onStop(); 41 Log.i("Rabbit", "onStop------"); 42 } 43 44 @Override 45 protected void onDestroy() { 46 super.onDestroy(); 47 Log.i("Rabbit", "onDestroy------"); 48 } 49 50 @Override 51 protected void onRestart() { 52 super.onRestart(); 53 Log.i("Rabbit", "onRestart------"); 54 } 55 56 @Override 57 protected void onSaveInstanceState(Bundle outState) { 58 super.onSaveInstanceState(outState); 59 outState.putString("info",mInfo); 60 Log.i("Rabbit", "onSaveInstanceState------info:"+mInfo); 61 } 62 63 @Override 64 protected void onRestoreInstanceState(Bundle savedInstanceState) { 65 super.onRestoreInstanceState(savedInstanceState); 66 String info=savedInstanceState.getString("info"); 67 Log.i("Rabbit", "onRestoreInstanceState------info:"+info); 68 } 69 70 @Override 71 public void onConfigurationChanged(Configuration newConfig) { 72 super.onConfigurationChanged(newConfig); 73 Log.i("Rabbit", "onConfigurationChanged------"); 74 } 75 76 @Override 77 public void onWindowFocusChanged(boolean hasFocus) { 78 super.onWindowFocusChanged(hasFocus); 79 Log.i("Rabbit", "onWindowFocusChanged------"); 80 } 81 82 }
测试结果图:
1、当Activity进入的时候,依次调用onCreate->onStart->onResume,进入运行状态。
2、当手机按下Home键回到手机桌面的时候,依次调用onPause->onStop,进入停滞状态。
3、当再次进入Activity的时候,依次调用onRestart->onStart->onResume,再次进入运行状态。
4、当Activity被其他Activity覆盖或被锁屏,系统会调用onPause方法,暂停当前Activity的执行。
5、当Activity由被覆盖状态回到前台或解锁屏,系统会调用onResume方法,再次进入运行状态。
6、当按下手机Back键,依次调用onPause->onStop->onDestroy,结束当前Activity。
上面是对Activity生命周期的初步演示,但仅仅了解这些是远远不够的,为了使程序更加健壮,用户体验更加友好,我们还需要去关注一些细节方面的东西。
这里我们需要额外的关注3个方法:onWindowFocusChanged、onSaveInstanceState、onRestoreInstanceState
1、onWindowFocusChanged:在Activity窗口获得或失去焦点时被调用;
(1)创建时首次呈现在用户面前;
(2)当前Activity被其他Activity覆盖;
(3)当前Activity转到其他Activity或按Home键回到主屏,自身退居后台;用户退出当前Activity。
当Activity被创建时onWindowFocusChanged是在onResume之后被调用,当Activity被覆盖或者退居后台或者当前Activity退出时,onWindowFocusChanged是在onPause之后被调用。
2、onSaveInstanceState:
(1)在Activity被覆盖或退居后台之后,系统资源不足将其杀死,此方法会被调用;
(2)在用户改变屏幕方向时,此方法会被调用;
(3)在当前Activity跳转到其他Activity或者按Home键回到主屏,自身退居后台时,此方法会被调用。
第一种情况我们无法保证什么时候发生,系统根据资源紧张程度去调度;
第二种是屏幕翻转方向时,系统先销毁当前的Activity,然后再重建一个新的,调用此方法时,我们可以保存一些临时数据;
第三种情况系统调用此方法是为了保存当前窗口各个View组件的状态。onSaveInstanceState的调用顺序是在onPause之后。
3、onRestoreInstanceState:
(1)在Activity被覆盖或退居后台之后,系统资源不足将其杀死,然后用户又回到了此Activity,此方法会被调用;
(2)在用户改变屏幕方向时,重建的过程中,此方法会被调用。我们可以重写此方法,以便可以恢复一些临时数据。
onRestoreInstanceState的调用顺序是在onStart之后。
我们来模拟下onSaveInstanceState和onRestoreInstanceState的使用:
首先我先在定义一个成员变量,在onCreate方法里赋值:
private String mInfo; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Log.i("Rabbit", "onCreate------"); mInfo="I Am Rabbit"; }
在onSaveInstanceState和onRestoreInstanceState方法里分别进行数据的保存和取出:
@Override protected void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); outState.putString("info",mInfo); Log.i("Rabbit", "onSaveInstanceState------info:"+mInfo); } @Override protected void onRestoreInstanceState(Bundle savedInstanceState) { super.onRestoreInstanceState(savedInstanceState); String info=savedInstanceState.getString("info"); Log.i("Rabbit", "onRestoreInstanceState------info:"+info); }
然后翻转屏幕看下日志打印效果:
从日志打印结果,我们可以很清楚的看到程序执行流程:
1、我们的Activity被销毁重建了,onSaveInstanceState在onPause之后被执行了,并保持了我们的变量值。
2、在Activity被重建获取焦点前(onResume前)执行了onRestoreInstanceState方法,并取出了我们先前保存的变量值。
知道这个流程,我们就可以用onSaveInstanceState和onRestoreInstanceState来保存一些临时变量,比如按钮状态,标志位等等等。
关于屏幕方向改变Activity会重建的应对策略:
1、指定为竖屏:在AndroidManifest.xml中对指定的Activity设置:
android:screenOrientation="portrait"
或者在onCreate方法中指定:
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); //竖屏
2、指定为横屏:在AndroidManifest.xml中对指定的Activity设置:
android:screenOrientation="landscape"
或者在onCreate方法中指定:
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); //横屏
3、锁定屏幕虽然可以实现我们想要的效果,但并不是很好的一种做法,为了避免这样销毁重建的过程,我们可以在AndroidMainfest.xml中对对应的<activity>配置:
android:configChanges="orientation"
如果是Android4.0,则是:
android:configChanges="orientation|keyboardHidden|screenSize"
然后我们在Activity里重写onConfigurationChanged方法:
@Override public void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); Log.i("Rabbit", "onConfigurationChanged------"); }
看下执行效果:
这样Activity在翻转屏幕的时候就不会被销毁重建了,只是调用了onConfigurationChanged方法。