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

本文详细探讨了Android中Activity的生命周期,包括onCreate、onStart、onResume、onPause、onStop和onDestroy等关键方法及其应用场景。文章强调了在不同生命周期方法中进行初始化、保存状态和释放资源的最佳实践,以及Activity间的切换逻辑。此外,还通过实例演示了如何测试Activity的生命周期和onSaveInstanceState方法。
摘要由CSDN通过智能技术生成

1.首先来一张生命周期的总图:

69da30b15ba9cd75d89728cbfbe7793a.png

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的实例化和启动

6b95a8a9918abc8c4e0e719ba273618a.png

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的暂停和继续

e5b0aa57b152f6bb8f88f6ea88429b31.png

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,如下:

8e2f64b160559a7e8a7debc43c0dbed7.png

1d3132a3bcbef8ef1d2727f59515ac6f.png

接着我们点击上面的"跳转",如下:

52b3c2c298ffd7fd09c99a0670728222.png

0d15ad0b0db7993f0ac7193f505b09f9.png

点击back键,如下:

63a95809453efb18ddf728eb815b9c72.png

再次点击back键,如下:

48c348de1718b05f20653a9b773b673b.png

(3)退出上面的应用程序,重新运行,然后点击Home键,Logcat如下:

df22a6c777c19575e2d3cdad22c8869d.png

点击程序,跳转到SecondActivity,再次点击Home键,Logcat如下:

9d3b988275def4ee131182d179b13c90.png

(4)退出应用程序,重新运行,然后竖屏显示转换为横屏显示,Logcat如下:

ced45e5d8d68d1d3a5ace1e96219dda5.png

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,如下:

a67cb1b5f4529febea968edb4ba0df62.png

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

7f0cd4a15acdd2caec23c6420ae496b5.png

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值