Android(java)学习笔记113:Activity的生命周期

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 package com.himi.saveactivitydemo;
 2 
 3 import android.app.Activity;
 4 import android.content.Intent;
 5 import android.os.Bundle;
 6 import android.view.View;
 7 
 8 public class MainActivity extends Activity {
 9     
10     private int mCount = 0;  
11     
12     @Override
13     protected void onCreate(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 void click(View view) {
27         Intent intent = new Intent(this, SecondActivity.class);
28         startActivity(intent);
29     }
30 
31     
32 
33     @Override
34     protected void onStart() {
35         // TODO Auto-generated method stub
36         super.onStart();
37         System.out.println("---MainActivity onStart---");
38     }
39 
40     @Override
41     protected void onRestart() {
42         // TODO Auto-generated method stub
43         super.onRestart();
44         System.out.println("---MainActivity onRestart---");
45     }
46 
47     @Override
48     protected void onResume() {
49         // TODO Auto-generated method stub
50         super.onResume();
51         System.out.println("---MainActivity onResume---");
52     }
53 
54     @Override
55     protected void onSaveInstanceState(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     @Override
64     protected void onPause() {
65         // TODO Auto-generated method stub
66         super.onPause();
67         System.out.println("---MainActivity onPause---");
68     }
69 
70     @Override
71     protected void onStop() {
72         // TODO Auto-generated method stub
73         super.onStop();
74         System.out.println("---MainActivity onStop---");
75     }
76 
77     @Override
78     protected void onDestroy() {
79         // TODO Auto-generated method stub
80         super.onDestroy();
81         System.out.println("---MainActivity onDestroy---");
82     }
83 
84     
85 }

SecondActivity,如下:

 1 package com.himi.saveactivitydemo;
 2 
 3 import android.app.Activity;
 4 import android.os.Bundle;
 5 
 6 public class SecondActivity extends Activity {
 7 
 8     @Override
 9     protected void onCreate(Bundle savedInstanceState) {
10         super.onCreate(savedInstanceState);
11         setContentView(R.layout.second);
12         System.out.println("---SecondActivity onCreate---");
13     }
14 
15 
16     @Override
17     protected void onStart() {
18         // TODO Auto-generated method stub
19         super.onStart();
20         System.out.println("---SecondActivity onStart---");
21     }
22 
23     @Override
24     protected void onRestart() {
25         // TODO Auto-generated method stub
26         super.onRestart();
27         System.out.println("---SecondActivity onRestart---");
28     }
29 
30     @Override
31     protected void onResume() {
32         // TODO Auto-generated method stub
33         super.onResume();
34         System.out.println("---SecondActivity onResume---");
35     }
36 
37     //为了防止万一程序被销毁的风险,这个方法可以保证重要数据的正确性  
38     //不写这个方法并不意味着一定出错,但是一旦遇到了一些非常奇怪的数据问题的时候  
39     //可以看看是不是由于某些重要的数据没有保存,在程序被销毁时被重置  
40     @Override
41     protected void onSaveInstanceState(Bundle outState) {
42         // TODO Auto-generated method stub
43         super.onSaveInstanceState(outState);
44         System.out.println("---SecondActivity onSaveInstanceState---");
45     }
46 
47     @Override
48     protected void onPause() {
49         // TODO Auto-generated method stub
50         super.onPause();
51         System.out.println("---SecondActivity onPause---");
52     }
53 
54     @Override
55     protected void onStop() {
56         // TODO Auto-generated method stub
57         super.onStop();
58         System.out.println("---SecondActivity onStop---");
59     }
60 
61     @Override
62     protected void onDestroy() {
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 package com.himi.saveactivitydemo;
 2 
 3 import android.app.Activity;
 4 import android.content.Intent;
 5 import android.os.Bundle;
 6 import android.view.View;
 7 
 8 public class MainActivity extends Activity {
 9     
10     private String name;
11     
12     @Override
13     protected void onCreate(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 void click(View view) {
27         Intent intent = new Intent(this, SecondActivity.class);
28         startActivity(intent);
29     }
30 
31     
32 
33     @Override
34     protected void onStart() {
35         // TODO Auto-generated method stub
36         super.onStart();
37         System.out.println("---MainActivity onStart---");
38     }
39 
40     @Override
41     protected void onRestart() {
42         // TODO Auto-generated method stub
43         super.onRestart();
44         System.out.println("---MainActivity onRestart---");
45     }
46 
47     @Override
48     protected void onResume() {
49         // TODO Auto-generated method stub
50         super.onResume();
51         System.out.println("---MainActivity onResume---");
52     }
53 
54     @Override
55     protected void onSaveInstanceState(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     @Override
63     protected void onRestoreInstanceState(Bundle savedInstanceState) {
64          name = savedInstanceState.getString("name"); //被重新创建后恢复缓存的数据
65          super.onRestoreInstanceState(savedInstanceState);
66          System.out.println("---MainActivity onRestoreInstanceState---");
67     }
68 
69     @Override
70     protected void onPause() {
71         // TODO Auto-generated method stub
72         super.onPause();
73         System.out.println("---MainActivity onPause---");
74     }
75 
76     @Override
77     protected void onStop() {
78         // TODO Auto-generated method stub
79         super.onStop();
80         System.out.println("---MainActivity onStop---");
81     }
82 
83     @Override
84     protected void onDestroy() {
85         // TODO Auto-generated method stub
86         super.onDestroy();
87         System.out.println("---MainActivity onDestroy---");
88     }
89 
90     
91 }

(2)部署程序到手机上,观察Logcat,如下:

 

然后将MainActivity竖屏显示 转换为 横屏显示,观察Logcat如下:

posted on 2015-08-17 21:47  鸿钧老祖  阅读(605)  评论(0编辑  收藏  举报

导航