1.首先来一张生命周期的总图:
onCreate():创建Acitivity界面
onStart():让上面创建的界面可见
onResume():让上面创建的界面中的点击事件生效,获得焦点
onPause():让上面创建的界面中的点击事件没有效果,失去焦点
onStop():让上面创建的界面不可见(最小化)
onDestory():销毁上面的创建的界面
(1)完整生命周期(entire lifetime):
onCreate()---> onStart()-->onResume()-->onPause()-->onStop()-->onDestory()
(2)可视生命周期(visible lifetime):
onStart()-->onResume()-->onPause()-->onStop()
(3)前台生命周期(foreground lifetime):
onResume-->onPause()
2.几个典型的场景
(1)Activity从被装载到运行,执行顺序如下:
onCreate() -> onStart() -> onResume();
(2)Activity从运行到暂停,再到继续回到运行
onPause() -> onResume ()
这个过程发生在Activity被别的Activity遮住了部分UI,失去了用户焦点,另外那个Activity退出之后,这个Activity再次获得运行。整个过程中,该Activity的实例是一直存在的。
(3)Activity运行到停止
onPause() -> onStop()
这个过程发生在Activity的UI完全被别的Activity遮住了,当然也失去了用户的焦点。这个过程中Activity的实例仍然存在。比如,当Activity运行的时候,用户了按了Home键,该Acitivity就会被执行。
(4)Activity从停止到运行
onReset() -> onStart() -> onResume()
处于Stopped状态并且实例仍然存在的Activity,再次被系统运行时,执行这个过程。这个过程是(3)的逆过程。
(5)Activity从运行到销毁,执行顺序如下:
onPause() -> onStop() -> onDestory()
这个过程发生在Activity完全停掉并被销毁了,所以该Activity的实例也就不存在了。比如这个Activity正在运行,用户按了Back按键,该Activity就会执行这个过程。这个过程是(1)的逆过程。
(6)被清除出内存的Activity的重新运行
onCreate() -> onStart() -> onResume()
这个过程对用户是透明的,用户不知道这个过程的发生。
3. 在谷歌官方文档中,这样说道每个生命周期方法的作用:
(1)onCreate
当activity第一次创建时调用.这里应该完成所有静态资源的建立, 比如使用setContentView(int)和布局资源定义你的UI视图, 使用findViewById(int)取出程序中需要交互的控件, 绑定数据.
此时视图还不存在,无法调用动画等.
还有需要注意, 每次activity启动, 不一定都会调用这个函数. 当当前activity只是被覆盖一部分, 当前activity再次可交互时,是只调用onResume方法, 不会调用onCreate方法.
(2) onStart
这里说明它不是activity对用户是否可见的最好的指示器
(3)onResume
打开独占设备,如相机,在onPause中释放.
(4)onPause
在这里系统将要离开当前Activity, 恢复其他activity. 用户在程序里做的任何改变都应该在此刻提交(通常用ContentProvide来保存数据). 还有需要在这里停止动画和其他耗费CPU的事件来确保转换到下一个activity的流畅度.
请记住:这个方法的实现必须很快完成, 不能占用太多时间, 因为在这个方法完成之前, 下一个activity不会恢复. 如果这个方法耗时较长, 就会影响用户体验. 如果对应的onPause()在500ms内还没有执行完,ActivityManagerService就会强制关闭这个Activity.
另外一个请记住的是:如果当前activity拥有独占资源(比如相机), 必须在这里释放, 以免在下一个activity中需要用到.
(5)onStop
请注意: 在内存不足而导致系统无法保留此进程的情况下, onStop() 可能不会被执行。
几乎所有Activity的子类,都会实现onCreate和onPause这两个方法.
4. 几个关于Activity生命周期方法的疑问 ?
(1)如果所有的初始化都在onCreate()中实现,会有什么问题?
首先,Activity的onCreate()被调用时,Activity还不可见,如果要做一些动画,既然视图还不存在,在onCreate中来启动动画,明显有问题。
其次,A Activity 切换到 B Activity,再切换到 A Activity(我们假定是A Activity的同一个实例),由于实例已经存在,所以onCreate不会再被调用,那A Activity从后台切换至前台时,有可能需要一些初始化,那就没法再被调用到了,也有问题。
(2)如果所有的初始化都在onStart()中实现,会有什么问题?
首先,onCreate()注释中,是明确建议 setContentView()、findViewById() 要在 onCreate() 中被调用,但我实测了一下,在onStart()中调用 setContentView()、findViewById() 功能也是正常的。
其次,onStart() 被调用时,Activity可能是可见了,但还不是可交互的,onStart() 的注释中都明确地说了这不是Activity对用户是可见的最好的指示器,onStart() 在这之前被调用,那有一些特殊的初始化相关的逻辑在这里被调用也会有问题。
(3)如果把所有的去初始化都在onStop()中实现,会有什么问题?
在 onResume() 的注释中,建议是在onResume()中打开独占设备(比如相机),与onResume()对应的是onPause(),所以所有的去初始化操作放在onStop()中执行,可能会引出新的问题;
在 onStop()的注释中明确地写了,在内存不足而导致系统无法保留此进程的情况下,onStop() 可能都不会被执行。
我的老Android手机的相机应用如果未正常关闭,相机在不重启系统的情况下就无法再正常启动,估计就和这个机制有关;相机进程是被强制杀掉的,而导致去初始化操作未被正常执行。
(4)Activity间跳转时,为什么是先A Activity的onPause()被调用,然后是B Activity的初始化流程(onCreate() --> onStart() --> onResume()),再然后是A Activity的onStop()被调用?
在 onResume() 的注释中,建议是在onResume()中打开独占设备(比如相机),与onResume()对应的是onPause(),关闭相机的操作也应该在此方法中被调用;否则,考虑一下如下场景:
如果A Activity打开了相机,我们点击某按钮要跳转到B Activity中,B Activity也想打开相机;假设A Activity的onPause() 在 BActivity启动后再被调用,
那B Activity根本就无法再正常启动相机。
在onPause() 的注释中,也明确地说了,在这个方法中执行停止动画等比较耗CPU的操作,如果不先执行这些操作,就先启动新应用,然后再来执行此操作,确实是不合逻辑;
从A Activity切换到B Activity的日志如下:
10-17 20:54:46.997: I/com.example.servicetest.A Activity(5817): onPause()1166919192 taskID=66
10-17 20:54:47.021: I/com.example.servicetest.B Activity(5817): onCreate() 1166971824 taskID=66
10-17 20:54:47.028: I/com.example.servicetest.B Activity(5817): onStart() 1166971824 taskID=66
10-17 20:54:47.028: I/com.example.servicetest.B Activity(5817): onResume() 1166971824 taskID=66
10-17 20:54:47.099: I/com.example.servicetest.A Activity(5817): onStop() 1166919192 taskID=66
从逻辑的完整性和用户体验的角度来分析,这样实现确实是比较合理的,当用户触发某事件切换到新的Activity,用户肯定是想尽快进入新的视图进行操作,
上面已经说了,在onResume()一般会打开独占设备,开启动画等,
当需要从AActivity切换到BActivity时,先执行AActivity中的与onResume()相对应的onPause()操作,比如关闭独占设备,关闭动画,或其它耗费cpu的操作;
以防止BActivity也需要使用这些资源,关闭耗CPU的操作,也有利于BActivity运行的流畅。
底层执行AActivity的onPause()时,有一定的时间限制的,当ActivityManagerService通知应用进程暂停指定的Activity时,如果对应的onPause()在500ms内还没有执行完,ActivityManagerService就会强制关闭这个Activity。如下就是对应的onPause()执行超时常量定义:
//How long we wait until giving up on the last activity to pause. This//is short because it directly impacts the responsiveness of starting the//next activity.
static final int PAUSE_TIMEOUT = 500; //定义在ActivityStack.java中
A Activity中比较消耗资源的部分关闭后,再切换到B Activity中执行B Activity的初始化,显示B Activity中的View。
当B Activity已经执行显示出来了,用户可以交互,后台再去执行A Activity的onStop()操作,即使这里面有些比较耗时的操作,也没有关系,这是在后台执行所以也不影响用户的体验。
A Activity跳转B Activity成功之后,如果用户点击Back键,将依次执行B:onPause -> A:onRestart -> A:onStart -> A:onResume -> B:onStop -> B:onDestroy。
当然此时肯定是来到A Activity之中。
接着上面,如果用户点击Home键,将依次执行A:onPause -> A:onStop。
倘若上面用户不是点击Home键,而是再次点击Back键,那么系统返回到桌面,并依次执行A:onPause -> A:onStop -> A:onDestroy。
5.Activity的实例化和启动
Acitivity实例的工作是android系统完成的,在用户点击执行一个Activity或者另一个Activity需要这个Activity执行时,如果这个Activity的实例不存在,Android系统都会实例化之,并且在该Activity所在线程的主线程中调用Activity的onCreate()方法,实现Activity的工作。
onCreate()是系统实例化Activity时,Activity可做的自身初始化的时机。在这里可以实例化变量,调用setContentView()设置UI显示内容。
一般来说,在Activity实例化之后就好启动该Activity,这样会在该Activity所在的进程的主线程中顺序调用Activity的onStart(),onResume()。onCreate()在Acitivity存续期中,只会被调用一次。如生命周期图中时序(6)的情形其实是另外又开启一个Activity的实例,并通过onCreate的参数传递进先前杀掉的Acitivity保存的信息。因为onStart()可因为已经停止了,再次执行而被调用多次。onResume()可以因为Activity的Paused/Resumed的不停转换,而被频繁调用。
6.Activity的暂停和继续
7.Activity的关闭/销毁与重新运行
因为处于Paused状态的Activity在内存极端不足的情况下,它所在的进程也可能被取消,这样onStop()在被取消前,不一定会被调用,这样的onPause()是比onStop()更适合的保留信息到永远存储区的时机。
Activity被销毁可能显式地按了Back按键,也可能是处于Paused或者Stopped状态,因为内存不足而被销毁。还有一种情况是配置信息改变(比如屏的方向改变)后,根据设置需要销毁掉所有的Activity(是否关闭还要看Activity自己的设置),再重新运行它们。
被系统隐式销毁的Activity,在被销毁(onStop()调用)之前,一般的会调用onSaveInstanceState()保留该Activity此时的状态信息。该办法中传入一个参数Bundle,可以在此方法中把此时的状态信息写入,系统保留这些。而当该Activity再次被实例化运行时,系统会保留在Bundler的信息再次以参数形式,通过onCreate()方法传入。
(1)onSaveInstanceState什么时候调用:
通常在onSaveInstanceState()中保留UI信息,永久存储的信息最好还是在onPause()保存。Activity的onSaveInstanceState()已经缺省实现来保留通用View的UI信息,所以不管是否保留当前Activity的信息,通常都在onSaveInstanceState()中调用super.onSaveInstanceState()来保留通用的UI信息。
当某个activity变得"容易"被系统销毁时,该activity的onSaveInstanceState()就会被执行,除非该activity是被用户主动销毁的,例如当用户按BACK键的时候,onSaveInstanceState()就不会被调用。因为在这种情况下,用户的行为决定了不需要保存Activity的状态。通常onSaveInstanceState()只适合用于保存一些临时性的状态,而onPause()适合用于数据的持久化保存。
注意上面的双引号,何为"容易"?意思就是说该activity还没有被销毁,而仅仅是一种可能性。这种可能性有哪些?
当用户按下HOME键时。这是显而易见的,系统不知道你按下HOME后要运行多少其他的程序,自然也不知道activity A是否会被销毁,因此系统会调用onSaveInstanceState(),让用户有机会保存某些非永久性的数据。以下几种情况的分析都遵循该原则
长按HOME键,选择运行其他的程序时。
按下电源按键(关闭屏幕显示)时。
从activity A中启动一个新的activity时。
屏幕方向切换时,例如从竖屏切换到横屏时。
当屏幕的方向发生了改变, Activity会被摧毁并且被重新创建,如果你想在Activity被摧毁前缓存一些数据,并且在Activity被重新创建后恢复缓存的数据。可以重写Activity的 onSaveInstanceState() 和onRestoreInstanceState()方法.
注意:在Activity的onCreate(Bundle savedInstanceState)方法里面,该方法的参数与onRestoreInstanceState(Bundle savedInstanceState)方法中的参数一致,因此在onCreate()方法中也能恢复缓存的数据。
(2)onRestoreInstanceState()什么时候调用
onRestoreInstanceState()被调用的前提是,activity A"确实"被系统销毁了,这里特别注意是系统杀死,不是人为编程finish等销毁的。而如果仅仅是停留在有这种可能性的情况下,则该方法不会被调用,例如,当正在显示activity A的时候,用户按下HOME键回到主界面,然后用户紧接着又返回到activity A,这种情况下activity A一般不会因为内存的原因被系统销毁,故activity A的onRestoreInstanceState方法不会被执行 此也说明上二者,大多数情况下不成对被使用。
onRestoreInstanceState()在onStart() 和 onPostCreate(Bundle)之间调用。
再比如:如果activity B启动后位于activity A的前端,在某个时刻activity A 因为系统回收资源的原因被杀掉了,A通过onSaveInstanceState将有机会保存其用户界面状态,使得将来用户返回到activity A时能通过onCreate(Bundle) 或者onRestoreInstanceState(Bundle)恢复界面的状态。
8.下面我们编写测试 Activity生命周期方法 和 onSaveInstanceState():
(1)新建一个Android工程,创建MainActivity,SecondActivity,如下:
MainActivity:
1 packagecom.himi.saveactivitydemo;2
3 importandroid.app.Activity;4 importandroid.content.Intent;5 importandroid.os.Bundle;6 importandroid.view.View;7
8 public class MainActivity extendsActivity {9
10 private int mCount = 0;11
12 @Override13 protected voidonCreate(Bundle savedInstanceState) {14 super.onCreate(savedInstanceState);15 if(savedInstanceState !=null) {16 int IntTest = savedInstanceState.getInt("IntTest");17 String StrTest = savedInstanceState.getString("StrTest");18
19 System.out.println("---savedInstanceState+IntTest="+IntTest+"+StrTest="+StrTest);20 }21 setContentView(R.layout.activity_main);22 System.out.println("---MainActivity onCreate---");23 mCount++;24 }25
26 public voidclick(View view) {27 Intent intent = new Intent(this, SecondActivity.class);28 startActivity(intent);29 }30
31
32
33 @Override34 protected voidonStart() {35 //TODO Auto-generated method stub
36 super.onStart();37 System.out.println("---MainActivity onStart---");38 }39
40 @Override41 protected voidonRestart() {42 //TODO Auto-generated method stub
43 super.onRestart();44 System.out.println("---MainActivity onRestart---");45 }46
47 @Override48 protected voidonResume() {49 //TODO Auto-generated method stub
50 super.onResume();51 System.out.println("---MainActivity onResume---");52 }53
54 @Override55 protected voidonSaveInstanceState(Bundle outState) {56 //TODO Auto-generated method stub
57 outState.putInt("IntTest", mCount);58 outState.putString("StrTest", "savedInstanceState test");59 super.onSaveInstanceState(outState);60 System.out.println("---MainActivity onSaveInstanceState---");61 }62
63 @Override64 protected voidonPause() {65 //TODO Auto-generated method stub
66 super.onPause();67 System.out.println("---MainActivity onPause---");68 }69
70 @Override71 protected voidonStop() {72 //TODO Auto-generated method stub
73 super.onStop();74 System.out.println("---MainActivity onStop---");75 }76
77 @Override78 protected voidonDestroy() {79 //TODO Auto-generated method stub
80 super.onDestroy();81 System.out.println("---MainActivity onDestroy---");82 }83
84
85 }
SecondActivity,如下:
1 packagecom.himi.saveactivitydemo;2
3 importandroid.app.Activity;4 importandroid.os.Bundle;5
6 public class SecondActivity extendsActivity {7
8 @Override9 protected voidonCreate(Bundle savedInstanceState) {10 super.onCreate(savedInstanceState);11 setContentView(R.layout.second);12 System.out.println("---SecondActivity onCreate---");13 }14
15
16 @Override17 protected voidonStart() {18 //TODO Auto-generated method stub
19 super.onStart();20 System.out.println("---SecondActivity onStart---");21 }22
23 @Override24 protected voidonRestart() {25 //TODO Auto-generated method stub
26 super.onRestart();27 System.out.println("---SecondActivity onRestart---");28 }29
30 @Override31 protected voidonResume() {32 //TODO Auto-generated method stub
33 super.onResume();34 System.out.println("---SecondActivity onResume---");35 }36
37 //为了防止万一程序被销毁的风险,这个方法可以保证重要数据的正确性38 //不写这个方法并不意味着一定出错,但是一旦遇到了一些非常奇怪的数据问题的时候39 //可以看看是不是由于某些重要的数据没有保存,在程序被销毁时被重置
40 @Override41 protected voidonSaveInstanceState(Bundle outState) {42 //TODO Auto-generated method stub
43 super.onSaveInstanceState(outState);44 System.out.println("---SecondActivity onSaveInstanceState---");45 }46
47 @Override48 protected voidonPause() {49 //TODO Auto-generated method stub
50 super.onPause();51 System.out.println("---SecondActivity onPause---");52 }53
54 @Override55 protected voidonStop() {56 //TODO Auto-generated method stub
57 super.onStop();58 System.out.println("---SecondActivity onStop---");59 }60
61 @Override62 protected voidonDestroy() {63 //TODO Auto-generated method stub
64 super.onDestroy();65 System.out.println("---SecondActivity onDestroy---");66 }67
68
69 }
(2)部署程序到手机上,同时观察Logcat,如下:
接着我们点击上面的"跳转",如下:
点击back键,如下:
再次点击back键,如下:
(3)退出上面的应用程序,重新运行,然后点击Home键,Logcat如下:
点击程序,跳转到SecondActivity,再次点击Home键,Logcat如下:
(4)退出应用程序,重新运行,然后竖屏显示转换为横屏显示,Logcat如下:
9.下面我们编写测试 Activity生命周期方法和 onRestoreInstanceState():
修改之前上面的测试代码
(1)修改后的MainActivity和SecondActivity,如下:
MainActivity如下:
1 packagecom.himi.saveactivitydemo;2
3 importandroid.app.Activity;4 importandroid.content.Intent;5 importandroid.os.Bundle;6 importandroid.view.View;7
8 public class MainActivity extendsActivity {9
10 privateString name;11
12 @Override13 protected voidonCreate(Bundle savedInstanceState) {14 super.onCreate(savedInstanceState);15 if(savedInstanceState !=null) {16
17 String str= savedInstanceState.getString("name");18
19 System.out.println("---savedInstanceState store str is:---"+str);20 }21 setContentView(R.layout.activity_main);22 System.out.println("---MainActivity onCreate---");23
24 }25
26 public voidclick(View view) {27 Intent intent = new Intent(this, SecondActivity.class);28 startActivity(intent);29 }30
31
32
33 @Override34 protected voidonStart() {35 //TODO Auto-generated method stub
36 super.onStart();37 System.out.println("---MainActivity onStart---");38 }39
40 @Override41 protected voidonRestart() {42 //TODO Auto-generated method stub
43 super.onRestart();44 System.out.println("---MainActivity onRestart---");45 }46
47 @Override48 protected voidonResume() {49 //TODO Auto-generated method stub
50 super.onResume();51 System.out.println("---MainActivity onResume---");52 }53
54 @Override55 protected voidonSaveInstanceState(Bundle outState) {56 //TODO Auto-generated method stub
57 outState.putString("name", "MainBoss");//被摧毁前缓存一些数据
58 super.onSaveInstanceState(outState);59 System.out.println("---MainActivity onSaveInstanceState---");60 }61
62 @Override63 protected voidonRestoreInstanceState(Bundle savedInstanceState) {64 name = savedInstanceState.getString("name"); //被重新创建后恢复缓存的数据
65 super.onRestoreInstanceState(savedInstanceState);66 System.out.println("---MainActivity onRestoreInstanceState---");67 }68
69 @Override70 protected voidonPause() {71 //TODO Auto-generated method stub
72 super.onPause();73 System.out.println("---MainActivity onPause---");74 }75
76 @Override77 protected voidonStop() {78 //TODO Auto-generated method stub
79 super.onStop();80 System.out.println("---MainActivity onStop---");81 }82
83 @Override84 protected voidonDestroy() {85 //TODO Auto-generated method stub
86 super.onDestroy();87 System.out.println("---MainActivity onDestroy---");88 }89
90
91 }
(2)部署程序到手机上,观察Logcat,如下:
然后将MainActivity竖屏显示 转换为 横屏显示,观察Logcat如下: