再谈Activity生命周期

来源:互联网 发布:云喇叭软件收费吗 编辑:程序博客网 时间:2024/06/07 00:46

再谈Activity生命周期

  开发过Android应用程序的猿们应该都知道Activity,我也接触Android一年多了,期间看过N多关于Activity生命周期的博客,甚至源码,但是对它的生命周期总是容易遗忘一些细节,今天再重新总结一下。

本文重点有两个:

1、  onSaveInstanceState(Bundle)方法的理解,即它究竟会在何时得到执行;

2、  当从ActivityA启动ActivityB时,如果ActivityB界面中存在“浑浊”区域时,即ActivityA部分界面仍然可见时,将不会执行到onStop方法,什么时候判断它是浑浊的?

还是先来一张经典的官方图片,先说说我的理解:


Activity启动时,首先执行onCreate()方法,在onCreate中我们需要完成界面布局加载、控件实例化、数据绑定等操作;之后onStart方法将得到执行,onStart方法执行的时机官方描述是:此时,Activity将要显示而又没有显示时执行onStart。怎么理解呢?就是显示界面所需数据(包括各种资源、控件大小位置)均已计算完成,执行完onStart后就立即绘制界面。界面绘制完成后,就会执行onResume方法,官方对onResume执行时机的描述是:界面已经完全显示,但是还不能实现与用户的交互。因此,当onResume执行完成后,就可以实现用户操作了。此时,activity位于任务栈的顶端,任何情况下,系统都不会主动关闭这个activity。前面介绍的onCreate、onStart、onResume三个方法,我们使用最多,执行的操作最多的就是onCreate了,至于其余两个方法,就看自己的需求了,我们可以在里面去实例化控件、绑定数据源,也可以什么都不做。   这部分比较简单,后面将出现多种情况,我们一一分析:

1、  ActivityA在任务栈顶端运行时,当有其他ActivityB被启动时,Activity将失去任务栈顶端位置,进入后台运行,此时,onPause方法将会得到执行。注意到onPause方法后面还有一个onStop方法,官方说,当“the activity is no longer visible”的时候会执行onStop方法,当ActivityB中存在透明区域时,即我们看屏幕时仍然然能看到ActivityA的部分界面时,onStop方法就不会执行。(这里我们先不讨论这究竟是一种什么状态,后面我会详细说明)  现在我们假设onStop没有得到执行,只执行了onPause,此时如果用户再次导航到ActivityA,那么onResume方法将得到执行,我们可以继续操作ActivityA了;如果onStop执行过,那么用户重新导航到ActivityA时,经历的过程就是onRestartàonStartàonResume;

2、  ActivityA在任务栈顶端运行时,用户点击返回键退出,此时执行的过程比较简单,就是onPauseàonStopàonDestory.

3、  ActivityA因为各种原因进入后台以后,不再拥有最高优先级,当系统内存告急时,系统可能就会干掉ActivityA。这里有两点我们需要注意,其实不怕被干掉,干掉了我重新恢复就行了,那么我们怎么才能恢复呢?第一,activity只有进入后台才有可能被系统干掉,那么activity进入后台必定会执行onPause方法,实际上,activity任何时候离开任务栈都必定会执行onPause方法,因此,我们在这里面进行数据的持久化保存,是安全可恢复的;另外,activity还有一个方法叫做onSaveInstanceState(Bundle),这里的这个Bundle包含有可用于恢复activity的全部数据,系统对其进行持久化保存,在activity下次启动时会传递给onCreate和onRestoreInstanceState方法。但是onSaveInstanceState的具体执行时机,官方说法是当系统要干掉activity之前调用它,我们很难判断出究竟何时执行它,网上也有很多讨论,下面我来谈谈我的理解。

 

onSaveInstanceState究竟会在何时得到执行?

   官方API文档说了很大一长串,很费解,于是我参考了网上的一些说法,比如这篇博客(http://www.cnblogs.com/perfy/p/3820491.html)里面就说了:onSaveInstanceState的调用遵循一个重要原则,即当系统未经你许可时销毁了你的activity,则 onSaveInstanceState会被系统调用,这是系统的责任,因为它必须要提供一个机会让你保存你的数据(当然你不保存那就随便你了)。似乎有些理解了,但是我还是不能够确切的知道onSaveInstanceState究竟会在何时得到执行,强迫症的我只有继续找答案,最后我终于注意到官方API文档最后一句说“If called, this method will occur before onStop().There are no guarantees about whether it will occur before or after onPause().”,这句话一下就提醒了我,因为只要任务栈顶端activity界面不浑浊(对浑浊的详细理解见后面),那么onPause和onStop都会得到执行,而onPause是只要activity进入后台就一定会执行;结合之前博客看到的“未经你许可”思想,那么只要没有调用Activity的finish方法(查看源码知道,点击返回键实际上也是调用的finish()方法),都是未经许可了,都会在onStop之前调用它。这下好办了:

a、 当按下Home键,离开了activity,但是我没有调用到finish方法,所以onSaveInstanceState会执行;

b、  当我从ActivityA启动ActivityB,A进入了后台,我没有调用finish方法,所以onSaveInstanceState会执行;

c、  屏幕横竖屏切换时、按电源键关闭屏幕是,我都没有调用finish方法,所以onSaveInstanceState会执行;

d、  当用户点击返回键,或者点击界面的退出功能按钮,直接或间接地调用了finish方法,所以onSaveInstanceState会执行;

所以总结下,android把自己说得太聪明了,它哪里知道后面会杀死这个activity,他不过就是把所有未退出的Activity的状态都进行保存,内存低的时候直接杀掉这个activity就行啦,才不会去调用onSaveInstanceState 所以这也就引出一点,onSaveInstanceState方法和 onRestoreInstanceState方法虽然看着是一对兄弟,很亲密,但是他们“不一定”是成对的被调用的,onRestoreInstanceState被调用的前提activity A“确实”被系统销毁了。

 

界面何时浑浊?

之前看到这里的时候,心里面就很敬佩Android,你想,当从activityA启动一个ActivityB的时候,如果ActivityB存在哪怕一丁点透明的地方,系统都能知道它“浑浊了”,ActivityA有部分可见那么就不能执行它的onStop方法?这个问题一直在我的脑海中,因此,今天我进行了测试。我弄了两个activity,A和B ,我把B的布局文件背景设置为android:background="@android:color/transparent",心想,我直接让他透明不就得了。就这样我进行了测试,当我看见结果时,我呆了,怎么B没有透明啊,白色的。。。这不科学。   于是我继续查阅了资料,这才发现其中的奥秘。   其实我们每个Activity的界面显示都是由一个就叫做window的对象管理着的,我们在布局文件里面设置了透明,只是使得这个window对象的内容透明了,但是window本身默认是不透明的,所以进一步测试我发现,android系统判断界面是否浑浊和我们能不能看见activityA一点关系也没有,只要我们把window设置为透明的,即使真正现实的界面布局哪怕一丁点缝隙不留,使得ActivityA完全不可见,onStop仍然不会执行,它判断的唯一依据就是这个window对象是否透明,那么怎么设置window透明呢?

这里给出两个方法(见博客http://blog.sina.com.cn/s/blog_4b53da1c01010nxe.html):

1.使用android内置的透明样式:

   在AndroidManifest.xml中的<activity>标签中添加   

   android:theme="@android:style/Theme.Translucent"

   其中,android:style/Theme.Translucent是android内置的透明样式

2.使用自定义的透明样式:

(1).res/values下建colors.xml文件:  

  <?xmlversion="1.0"encoding="UTF-8"?>  

  <resources>   

  <colorname="transparent">#9000</color>  

  </resources>

  这个值设定了整个界面的透明度,为了看得见效果,现在设为透明度为56%(9/16)左右。   

(2).res/values/下建styles.xml:   

  <?xmlversion="1.0"encoding="utf-8"?>  

  <resources>   

  <stylename="Transparent">   

  <itemname="android:windowBackground">@color/transparent</item>  

  <itemname="android:windowIsTranslucent">true</item>  

  <itemname="android:windowAnimationStyle">@+android:style/Animation.Translucent</item>  

  </style>   

  </resources>

(3).设置andrdoi:theme:  

  在AndroidManifest.xml中的任意<activity>标签中添加   

  android:theme="@style/transparent"

 后注:android:theme有很多使用方法,可以设置Activity为多种类型,如此类的透明背景,无标题栏,显示为对话框模式,桌面背景等,后面会有专门内容介绍。

 

以上内容都是经过我的测试的,为避免篇幅过长,具体测试代码,见Github仓库:https://github.com/BBigBoy/AndroidBaseTest

任何疑问,请直接回复联系。

0 0