Android(java)学习笔记170: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:
package com.himi.saveactivitydemo; import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View; public class MainActivity extends Activity { private int mCount = 0; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if(savedInstanceState !=null) {
int IntTest = savedInstanceState.getInt("IntTest");
String StrTest = savedInstanceState.getString("StrTest"); System.out.println("---savedInstanceState+IntTest="+IntTest+"+StrTest="+StrTest);
}
setContentView(R.layout.activity_main);
System.out.println("---MainActivity onCreate---");
mCount++;
} public void click(View view) {
Intent intent = new Intent(this, SecondActivity.class);
startActivity(intent);
} @Override
protected void onStart() {
// TODO Auto-generated method stub
super.onStart();
System.out.println("---MainActivity onStart---");
} @Override
protected void onRestart() {
// TODO Auto-generated method stub
super.onRestart();
System.out.println("---MainActivity onRestart---");
} @Override
protected void onResume() {
// TODO Auto-generated method stub
super.onResume();
System.out.println("---MainActivity onResume---");
} @Override
protected void onSaveInstanceState(Bundle outState) {
// TODO Auto-generated method stub
outState.putInt("IntTest", mCount);
outState.putString("StrTest", "savedInstanceState test");
super.onSaveInstanceState(outState);
System.out.println("---MainActivity onSaveInstanceState---");
} @Override
protected void onPause() {
// TODO Auto-generated method stub
super.onPause();
System.out.println("---MainActivity onPause---");
} @Override
protected void onStop() {
// TODO Auto-generated method stub
super.onStop();
System.out.println("---MainActivity onStop---");
} @Override
protected void onDestroy() {
// TODO Auto-generated method stub
super.onDestroy();
System.out.println("---MainActivity onDestroy---");
} }
SecondActivity,如下:
package com.himi.saveactivitydemo; import android.app.Activity;
import android.os.Bundle; public class SecondActivity extends Activity { @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.second);
System.out.println("---SecondActivity onCreate---");
} @Override
protected void onStart() {
// TODO Auto-generated method stub
super.onStart();
System.out.println("---SecondActivity onStart---");
} @Override
protected void onRestart() {
// TODO Auto-generated method stub
super.onRestart();
System.out.println("---SecondActivity onRestart---");
} @Override
protected void onResume() {
// TODO Auto-generated method stub
super.onResume();
System.out.println("---SecondActivity onResume---");
} //为了防止万一程序被销毁的风险,这个方法可以保证重要数据的正确性
//不写这个方法并不意味着一定出错,但是一旦遇到了一些非常奇怪的数据问题的时候
//可以看看是不是由于某些重要的数据没有保存,在程序被销毁时被重置
@Override
protected void onSaveInstanceState(Bundle outState) {
// TODO Auto-generated method stub
super.onSaveInstanceState(outState);
System.out.println("---SecondActivity onSaveInstanceState---");
} @Override
protected void onPause() {
// TODO Auto-generated method stub
super.onPause();
System.out.println("---SecondActivity onPause---");
} @Override
protected void onStop() {
// TODO Auto-generated method stub
super.onStop();
System.out.println("---SecondActivity onStop---");
} @Override
protected void onDestroy() {
// TODO Auto-generated method stub
super.onDestroy();
System.out.println("---SecondActivity onDestroy---");
} }
(2)部署程序到手机上,同时观察Logcat,如下:
接着我们点击上面的"跳转",如下:
点击back键,如下:
再次点击back键,如下:
(3)退出上面的应用程序,重新运行,然后点击Home键,Logcat如下:
点击程序,跳转到SecondActivity,再次点击Home键,Logcat如下:
(4)退出应用程序,重新运行,然后竖屏显示转换为横屏显示,Logcat如下:
9.下面我们编写测试 Activity生命周期方法 和 onRestoreInstanceState():
修改之前上面的测试代码
(1)修改后的MainActivity和SecondActivity,如下:
MainActivity如下:
package com.himi.saveactivitydemo; import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View; public class MainActivity extends Activity { private String name; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if(savedInstanceState !=null) { String str= savedInstanceState.getString("name"); System.out.println("---savedInstanceState store str is:---"+ str);
}
setContentView(R.layout.activity_main);
System.out.println("---MainActivity onCreate---"); } public void click(View view) {
Intent intent = new Intent(this, SecondActivity.class);
startActivity(intent);
} @Override
protected void onStart() {
// TODO Auto-generated method stub
super.onStart();
System.out.println("---MainActivity onStart---");
} @Override
protected void onRestart() {
// TODO Auto-generated method stub
super.onRestart();
System.out.println("---MainActivity onRestart---");
} @Override
protected void onResume() {
// TODO Auto-generated method stub
super.onResume();
System.out.println("---MainActivity onResume---");
} @Override
protected void onSaveInstanceState(Bundle outState) {
// TODO Auto-generated method stub
outState.putString("name", "MainBoss");//被摧毁前缓存一些数据
super.onSaveInstanceState(outState);
System.out.println("---MainActivity onSaveInstanceState---");
} @Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
name = savedInstanceState.getString("name"); //被重新创建后恢复缓存的数据
super.onRestoreInstanceState(savedInstanceState);
System.out.println("---MainActivity onRestoreInstanceState---");
} @Override
protected void onPause() {
// TODO Auto-generated method stub
super.onPause();
System.out.println("---MainActivity onPause---");
} @Override
protected void onStop() {
// TODO Auto-generated method stub
super.onStop();
System.out.println("---MainActivity onStop---");
} @Override
protected void onDestroy() {
// TODO Auto-generated method stub
super.onDestroy();
System.out.println("---MainActivity onDestroy---");
} }
(2)部署程序到手机上,观察Logcat,如下:
然后将MainActivity竖屏显示 转换为 横屏显示,观察Logcat如下:
Android(java)学习笔记170:Activity的生命周期的更多相关文章
- Android开发学习之路--Activity之生命周期
其实这篇文章应该要在介绍Activity的时候写的,不过那个时候还不怎么熟悉Activity,还是在这里详细介绍下好了.还是参考下官方文档的图吧: 从上面的流程,我们可以看出首先就是打开APP,开始执 ...
- Java学习笔记之——线程的生命周期、线程同步
一. 线程的生命周期 新建(new Thrad):创建线程后,可以设置各个属性值,即启动前 设置 就绪(Runnable):已经启动,等待CPU调动 运行(Running):正在被CPU调度 阻塞(B ...
- Android SDK上手指南:Activity与生命周期
Android SDK上手指南:Activity与生命周期 2013-12-26 15:26 核子可乐译 51CTO 字号:T | T Activity生命周期并不仅仅在用户运行应用程序之后才开始生效 ...
- android学习四(Activity的生命周期)
要学好活动(Activity).就必需要了解android中Activity的声明周期.灵活的使用生命周期.能够开发出更好的程序,在android中是使用任务来管理活动的,一个任务就是一组存放在栈里的 ...
- Android开发艺术探索读书笔记——01 Activity的生命周期
http://www.cnblogs.com/csonezp/p/5121142.html 新买了一本书,<Android开发艺术探索>.这本书算是一本进阶书籍,适合有一定安卓开发基础,做 ...
- android开发艺术探索学习 之 结合Activity的生命周期了解Activity的LaunchMode
转载请标明出处: http://blog.csdn.net/lxk_1993/article/details/50749728 本文出自:[lxk_1993的博客]: 首先还是先介绍下Activity ...
- Android开发艺术1之Activity的生命周期
作为<Android开发艺术探索>这本书的第一篇博客,我就多说几句.本系列博客旨在对书中相关内容进行解读,简化,提供一个入门到提高的流程.不敢说书评,也不能说教程,只希望对有些人有帮助就好 ...
- Android 横屏切换竖屏Activity的生命周期(转)
曾经遇到过一个面试题,让你写出横屏切换竖屏Activity的生命周期.现在给大家分析一下他切换时具体的生命周期是怎么样的: 1.新建一个Activity,并把各个生命周期打印出来 2.运行Acti ...
- Android(java)学习笔记171:Service生命周期
1.Service的生命周期 Android中的Service(服务)与Activity不同,它是不能和用户交互,不能自己启动的,运行在后台的程序,如果我们退出应用的时候,Servic ...
- Android(java)学习笔记114:Service生命周期
1.Service的生命周期 Android中的Service(服务)与Activity不同,它是不能和用户交互,不能自己启动的,运行在后台的程序,如果我们退出应用的时候,Servic ...
随机推荐
- Android使用开源框架加载图片
Android开发时,有时候需要们来加载网络图片,我们可以通过api的方式进行加载,但是前几天做的时候,发现了一个优秀的开源框架,可以帮助我们非常简单便捷的进行图片的加载,所以记录一下. 我所用的是: ...
- 【POJ 1741】 Tree (树的点分治)
Tree Description Give a tree with n vertices,each edge has a length(positive integer less than 100 ...
- SPRING IN ACTION 第4版笔记-第二章WIRING BEANS-008-在XML配置文件中引入JAVA配置文件 <import> 、<bean>
一.在xml中引入xml,用<import> <?xml version="1.0" encoding="UTF-8"?> <be ...
- android ListView异步加载图片(双缓存)
首先声明,参考博客地址:http://www.iteye.com/topic/685986 对于ListView,相信很多人都很熟悉,因为确实太常见了,所以,做的用户体验更好,就成了我们的追求... ...
- 子查询解嵌套in改写为exists
SELECT * FROM (SELECT pubformdat0_.id id332_, pubformdat0_.domain_id domain2_332_, pubformdat0_.proc ...
- android Button 颜色的变化(点击,放开,点击不放)
参考: http://endual.iteye.com/blog/1534258 总结: 定义res/drawable/button_style.xml文件 <?xml version=&quo ...
- Away3D基础之摄像机
转自:http://blog.csdn.net/cceevv/article/details/8571860 原英文地址:http://www.flashmagazine.com/Tutorials/ ...
- PowerDesigner 怎么给 Table Properties 增加注释和默认值
1. 选中表,右键 2. 选中“comment”, 这个就是列的注释 3.还是这个页面 ,往下有个“default value”, 这个就是你设置的默认值. 4. 这个是怎么设置默认值.
- java数据类型和运算优先级
一.数据类型 1.基本数据类型: . 布尔类型:boolean(true,false) . 整型:byte(-128,127).short(-32768,32767).int(-2147483648, ...
- phpDesigner 工具快捷键巧用
Zend Studio工具默认的快捷方式, 如果你从事php工作, 自然能够体会到一些便利性, 比如CTRL+D, 可以直接复制当前一行, 这对于重复代码及调试都有很大帮助. Ctrl+U转换大小写之 ...