运行状态
当一个活动位于栈顶的时候,该活动就处于运行状态。(Android是使用任务栈来管理活动的,也称返回栈(Back Stack)。在默认情况下,每当我们启动一个新的活动,它会在返回栈中入栈,并处于栈顶位置。每当我们按下Back键或调用finish()方法去销毁一个活动时,处于栈顶的活动会出栈,这时前一个入栈的活动会位于栈顶。系统总是会显示处于栈顶的活动给用户。)
暂停状态
当一个活动不再处于栈顶的位置,但仍然可见时,这时活动就进入了暂停状态。处于暂停状态的活动是完全存活的。
停止状态
当一个活动不再处于栈顶位置,并且完全不可见的时候,就进入了停止状态。
销毁状态
当一个活动从返回栈中移除后就变成了销毁状态。
(1)Activity启动:onCreate()→onStart()→onResume()
(2)点击Home键回到主界面/打开新的Activity:onPause()→onStop()
注:有一种特殊情况,如果新Activity采用了透明主题,那么当前Activity不会回调onStop()
(3)再次回到原Activity时:onRestart()→onStart()→onResume()
(4)退出当前Activity时:onPause()→onStop()→onDestroy()
(5)当执行到onPause()方法Activity失去焦点时,重新回到前台会执行onResume()方法,如果此时进程被销毁Activity重新执行时会先执行onCreate()方法。
(6)当执行到onStop()方法Activity不可见时,再次回到前台会执行onRestart()方法,如果此时进程被销毁Activity会重新执行onCreate()方法。
(7)两个Activity(A、B)切换(B是正常的Activity)的生命周期:onPause(A)->onCreate(B)->onStart(B)->onResume(B)->oStop(A)。这时如果按回退键回退到A,生命周期为:onPause(B)->onRestart(A)->onStart(A)->onResume(A)->oStop(B)。如果在切换到B后调用了A.finish(),则会走到onDestory(A),这时点回退键会退出应用。
(8)两个Activity(A、B)切换(B透明主题的Activity或是Dialog风格的Acivity)的生命周期:onPause(A)->onCreate(B)->onStart(B)->onResume(B)。这时如果回退到A ,生命周期为:onPause(B)->onResume(A)->oStop(B)->onDestory(B)。
(1)不设置Activity的android:configChanges时,切屏时会重新调用各自的生命周期,切横屏时会执行一次,切竖屏时会执行两次。
(2)切换Activity的android:configChanges="orientation"时,切屏时还是会重新调用各自的生命周期,切横、竖屏时只会执行一次。
(3)设置Activity的android:congifChanges="orientation|keyboardHidden"时,切屏时不会重新调用各自的生命周期,只会执行onConfigurationChanged()方法。
注:切换横竖屏时,若想保存网页数据,可以通过重写onSaveInstanceState()方法实现;若想恢复数据,则可通过重写onRestoreInstanceState()方法实现。
Activity是通过Intent来启动的,在启动时分两种情况,一种是显式启动,一种是隐式启动,具体如下:
(1)显式启动
该启动方式比较快速,创建Intent后直接指定包名和类名即可。
(2)隐式启动
该启动方式不显式指定组件,而是通过动作、类型、数据匹配对应的组件。
使用隐式子Intent需要注意:
启动模式一共有4种,分别是standard(叠加)、singleTop(栈顶复用)、singleTask(栈内复用)和singleInstance(在应用程序和系统中的唯一性),可以在AndroidManifest.xml中通过给< activity >标签指定android:launchMode属性来选择启动模式。
1、standard(默认模式)
standard是Activity默认的启动模式,特点是,每启动一个Activity就会在栈顶创建一个新的实例,在不进行显示指定的情况下,所有活动都会自动适应这种启动模式。对于使用standard模式的活动,系统不会在乎这个活动是否已经在返回栈中存在,每次启动都会创建一个新的实例。
示例如下:
运行程序,在MainActivity中连续点击3次按钮,logcat打印信息如下图所示:
每点击一次按钮,就会新创建出一个新的MainActivity实例。此时返回栈中存在4个MainActivity实例(程序启动时也算一次),因此需要连续点击4次Back键才能退出程序。
应用场景:闹钟程序。
2、singleTop(栈顶复用模式)
当活动的启动模式指定位singleTop,在启动活动时,首先会判断要启动的Activity是否位于栈顶,如果位于栈顶则直接复用,否则创建新的实例。
示例如下:
修改启动模式,运行程序,可以看到已经创建了一个MainActivity实例,之后不管多少次点击按钮都不会再有新的打印信息。因为当前MainActivity已经处于返回栈的栈顶,每次想要再启动一个新的MainActivity时都会直接使用栈顶的活动,因此MainActivity只有一个实例,仅按一次Back键就可以退出程序。
当MainActivity并未处于栈顶位置时,这时再启动MainActivity,还是会创建新的实例。
在FirstActivity中再次启动MainActivity时,栈顶活动已经变成了FirstActivity,因此会创建一个新的MainActivity实例。
应用场景:浏览器的书签、通讯消息聊天界面。
3、singleTask(栈内复用模式)
当活动的启动模式指定为singleTask,每次启动该活动的时候系统会首先在返回栈中检查是否有存在该活动的实例,如果发现以及存在则直接使用该实例,并把在这个活动之上的所有活动统统出栈,如果没有发现就会创建一个新的活动实例。
示例如下:
在MainActivity点击按钮进入FirstActivity,然后在FirstActivity点击按钮,又重新回到MainActivity。
现在返回栈中只剩下一个FirstActivity的实例,点击一次Back键就可以退出程序。
应用场景:浏览器主界面。
4、singleInstance(单实例模式)
指定为singleInstance模式的活动会启用一个新的返回栈来管理这个活动(如果singleTask模式指定了不同的taskAffinity,也会启动一个新的返回栈)。在这种模式下,会有一个单独的返回栈来管理这个活动,不管是哪个应用程序来访问这个活动,都共同的用一个返回栈,也就解决了共享活动实例的问题。
Activity采用singleInstance模式启动分两种情况:一种是要启动的Activity不存在,则系统会先创建一个新的任务栈,然后再创建Activity实例。一种是要启动的Activity已存在,无论当前Activity位于哪个程序哪个任务栈,系统都会把Activity所在的任务栈转移到前台,从而使Activity显示。
在该模式下,只有一个实例,并且这个实例独立运行在一个任务栈中,该任务栈不允许有别的Activity存在。
示例如下:
指定FirstActivity的启动模式为singleInstance,修改程序输出每一个活动的Task id。
由上图可以看到,FirstActivity的Task id不同于MainActivity和SecondActivity,这说明FirstActivity确实是放在一个单独的返回栈里面的,而且这个栈中只有FirstActivity这一个活动。
(1)以singleInstance模式启动的Activity具有全局唯一性,即整个系统中只存在一个这样的实例。
(2)以singleInstance模式启动的Activity在整个系统中是单例,如果在启动这样的Activity时,已经存在了一个实例,那么会把它所在的任务调度到前台,重用这个实例。
(3)以singleInstance模式启动的Activity具有独占性,即它会独自占用一个任务,被它开启的任何Activity都会运行在其他任务中。
(4)被singleInstance模式的Activity开启的其他Activity,能够在新的任务中启动,但不一定开启新的任务,也可能在已有的一个任务中开启。
应用场景:来电界面、浏览器(将浏览器设置为单例模式)。
补充:如何给Activity指定启动模式?
(1)通过AndroidManifest.xml文件为Activity指定启动模式。
(2)通过在Intent中设置标志位来为Activity指定启动模式。
二者的区别:①首先,优先级上,第二种方式的优先级要高于第一种,当两种同时存在时,以第二种方式为准;②其次,在限定范围上,第一种方式无法直接为Activity设定FLAG_ACTIVITY_CLEAR_TOP标识,而第二种方式无法为Activity指定singleInstance模式。
Activity提供了一个startActivityForResult(Intent intent, int requestCode)方法,该方法也用于启动Activity,并且这个方法可以在当前Activity销毁时返回一个结果给上一个Activity,实现数据回传功能。
在实际开发中这种功能很常见,如发朋友圈时,进入图库选择好照片后,会返回到发表状态页面并带回所选的图片信息。
在一个Activity中很可能调用startActivityForResult()方法启动多个不同的Activity,每一个Activity返回的数据都会回调onActivityResult()这个方法,因此,首先要做的就是检查requestCode的值来判断数据来源,确定数据是从哪一个Activity返回的,然后通过resultCode的值来判断数据处理结果是否成功,最后从data中取出数据,这样就完成了Activity数据返回的功能。
PendingIntent是延时意图,可以看作是对Intent的包装,主要用于处理非即时Intent,供当前App与外部App调用。PendingIntent主要持有的信息是它所包装的Intent和当前的App Context,即使当前App已经不存在了,也可以通过存在于PendingIntent中的Context来执行Intent。例如,当用户点击通知栏中的消息时,跳转到App的某个页面。
Intent与PendingIntent的区别主要有以下几点:
(1)Intent是即时启动,随所在的Activity的消失而消失,而PendingIntent用于处理非即时Intent。
(2)Intent在程序结束后终止,而PendingIntent在程序结束后依然有效。
(3)Intent需要在某个Context内运行,而PendingIntent自带Context。
(4)Intent在原Task中运行,而PendingIntent在新的Task中运行。
(5)Intent一般用于Activity、Service、BroadcastReceuver之间传递数据,而PendingIntent一般用于消息通知上,可以理解为延迟执行Intent。
Activity被系统回收有3种情况,具体如下:
(1)每个手机的内存是有限制的,当Android系统发现内存不足时,它会将后台运行的一些程序杀死,回收这部分内存。
(2)如果没有对横竖屏切换的情况进行任何处理,那么在Activity进行横竖屏切换时,Activity会先被完全销毁回收,然后再被重新创建,导致页面数据丢失。
(3)当App长期在后台运行时,有时出于省点等节省资源的目的,系统也会将APP回收掉。
Activity中提供了一个onSavedInstanceState(Bundle obj)方法,当系统销毁Activity时,会将Activity的状态信息以键值对的形式存放在bundle对象中。开发者可以重写Activity的onSavedInstanceState()方法,将要保存的页面数据全部存到bundle对象中。加入Activity被回收了,那么下次再进入这个Activity时就一定会调用onCreate()方法,开发者可以在onCreate()方法中通过bundle对象中保存的用户数据来做一些恢复数据的工作,防止Activity被系统回收时造成用户数据丢失。
当Activity被系统回收后,相应的用户数据自然也会被回收掉。同时,页面上的某些功能可能会依赖于某些页面数据,如果数据被回收了,那么当进入页面时,可能会造成一些异常,导致应用程序崩溃。
Activity被主动回收时,如按下Back键,系统不会保存它的状态,只有被动回收时,虽然这个Activity实例已被销毁,但系统在新建一个Activity实例时,会带上先前被回收Activity的信息。在当前Activity被销毁前调用onSaveInstanceState(onPause和onStop之间保存),重新创建Activity后会在onCreate后调用onRestoreInstanceState(onStart和onResume之间被调用),它们的参数Bundle用来数据保存和读取的。
保存View状态有两个前提:①View的子类必须实现了onSaveInstanceState;②必须要设定ID,这个ID作为Bundle的Key。