欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

Android中Activity生命周期和启动模式详解

程序员文章站 2024-03-31 17:36:58
activity生命周期经典图解: 按键对生命周期的影响: back键:   当我们按back键时,我们这个应用程序将结束,这时候我们将先后调用onpau...

activity生命周期经典图解:

Android中Activity生命周期和启动模式详解

按键对生命周期的影响:

back键:

  当我们按back键时,我们这个应用程序将结束,这时候我们将先后调用onpause()->onstop()->ondestory()三个方法。

再次启动app时,会执行oncreate()->onstart()->onresume()

home键:

  当我们打开应用程序时,比如浏览器,我正在浏览nba新闻,看到一半时,我突然想听歌,这时候我们会选择按home键,然后去打开音乐应用程序,而当我们按home的时候,activity先后执行了onpause()->onstop()这两个方法,这时候应用程序并没有销毁。

而当我们从桌面再次启动应用程序时,则先后分别执行了onrestart()->onstart()->onresume()三个方法。

一般activity切换正常生命周期(这里的一般是指启动模式为standard,切换activity时没有加flag标志):

activitya启动activityb:

activitya 的生命周期onpause()->onstop(),

activityb的生命周期oncreate()->onstart()->onresume()。

activityb执行finish返回activitya:

activityb的生命周期onpause()->onstop()->ondestory()

activitya的生命周期了onrestart()->onstart()->onresume()

注意:当activityb定义为dialog样式时,activitya的生命周期是不一样的,

我们给activityb加上theme

<style name="mydialogstyle"> 
   <item name="android:windowbackground">@android:color/transparent</item> 
   <item name="android:windowframe">@null</item> 
   <item name="android:windownotitle">true</item> 
   <item name="android:windowisfloating">true</item> 
   <item name="android:windowistranslucent">true</item> 
   <item name="android:windowcontentoverlay">@null</item> 
   <item name="android:windowanimationstyle">@android:style/animation.dialog</item> 
   <item name="android:backgrounddimenabled">true</item> 
 </style> 

这个时候,activitya启动activityb,b没有完全遮挡a,activityb的生命周期跟刚才一样,但是activitya并没有执行onstop()

还有一点需要特别注意,activity中直接弹dialog,acitivity的生命周期是不会变化的。网上有些说法是会执行onpause(),其实并没有执行!

另外还有几个跟生命周期相关的方法

@override 
 protected void onnewintent(intent intent) { 
   super.onnewintent(intent); 
 } 
 @override 
 protected void onsaveinstancestate(bundle outstate) { 
   super.onsaveinstancestate(outstate); 
 } 
 @override 
 protected void onrestoreinstancestate(bundle savedinstancestate) { 
   super.onrestoreinstancestate(savedinstancestate); 
 } 
 @override 
 public void onconfigurationchanged(configuration newconfig) { 
   super.onconfigurationchanged(newconfig); 
 } 

当应用运行起来后就会开启一条线程,线程中会运行一个任务栈,当activity实例创建后就会放入任务栈中。activity启动模式的设置在androidmanifest.xml文件中,通过配置activity的属性android:launchmode=""设置。

1. standard模式(默认)

我们平时直接创建的activity都是这种模式的activity,这种模式的activity的特点是:只要你创建了activity实例,一旦激活该activity,则会向任务栈中加入新创建的实例,退出activity则会在任务栈中销毁该实例。
standard模式是所启动的activity都是在同一个task容器栈下,不会重新创建新的task容器栈。先压入栈的activity实例按顺序入栈底,后入栈在栈顶,处于栈的顶部activity实例处于活动状态,其他处于非活动状态。按物理返回键,退出当前所处活动状态activity窗口,这样就会从task容器栈中弹出,显示在手机主屏幕上,从而,有非活动状态转换成活动的状态。其次,standard容器栈可能会存在着相同的activity实例,只有没调用一次startactivity方法,就会创建目标activity实例对象压入task容器栈。
如果activity启动顺序为a->b->b->a->d,栈中的acitivy为abbad(最先创建的a位于栈底,最后创建的d位于栈顶)

2. singletop模式

这种模式会考虑当前要激活的activity实例在任务栈中是否正处于栈顶,如果处于栈顶则无需重新创建新的实例,会重用已存在的实例,否则会在任务栈中创建新的实例。
singletop有个不错的用法是防止多次点击创建多个activity,无论start几次,singletop模式能保证栈顶只有一个实例。 如果activity启动顺序为a->b->b->a->d,栈中的acitivy为abad(当b位于栈顶时,再次启动b的时候,b不会重新创建)

3. singletask模式

如果任务栈中存在该模式的activity实例,则把栈中该实例以上的activity实例全部移除,调用该实例的newinstance()方法重用该activity,使该实例处於栈顶位置,否则就重新创建一个新的activity实例。
singletask模式,特别需要注意了。启动的目标activity实例如果已经存在task容器栈中,不管当前实例处于栈的任何位置,是栈顶也好,栈底也好,还是处于栈中间,只要目标activity实例处于task容器栈中,都可以重用该activity实例对象,然后,把处于该activity实例对象上面全部activity实例清除掉,并且,task容器栈中永远只有唯一实例对象,不会存在两个相同的实例对象。所以,如果你想你的应用不管怎么启动目标activity,都只有唯一一个实例对象,就使用这种启动模式。 如果activity启动顺序为a->b->b->a->d,栈中的acitivy为ad(当a再次被启动时,a会被移到栈顶,位于a上面的acitivity全部会出栈)

4. singleinstance模式

当该模式activity实例在任务栈中创建后,只要该实例还在任务栈中,即只要激活的是该类型的activity,都会通过调用实例的newinstance()方法重用该activity,此时使用的都是同一个activity实例,它都会处于任务栈的栈顶。此模式一般用于加载较慢的,比较耗性能且不需要每次都重新创建的activity。

singleinstance启动模式,简单说就是可以共享某个activity。比如,应用1的任务容器栈中创建了mainactivity实例,应用2也要激活mainactivity,则不需要创建mainactivity实例,直接可以公用mainactivity实例。 尤其值得注意:应用1启动mainactivity,按home键;打开应用2启动应用1的mainactivity实例。在按home键,打开应用1,这时候应用1的界面是应该是处于mainactivity界面实例。 singleinstance的一个任务栈中只有一个activity,并保证不再有其他activity实例进入。

特别需要注意的生命周期onnewintent

当一个activity被start,而不需要重新创建时,就会执行onnewintent生命周期。如果一个activity的启动模式是singletask,我们可以在onnewintent中执行一些刷新操作等。

我们一般会把mainacitivy设置为singletask,除了保证mainactivity的唯一,还可以利用singletask的特性做一些清理工作。自动管理栈,销毁无用的acitivity.

intent flags

 flags: 表示intent的标志位,常用于activity的场景中,它和activity的启动模式有着密切的联系。

下面列举的是和本文主题相关的flags属性:

intent.flag_activity_new_task (默认)

默认的跳转类型,它会重新创建一个新的activity,不过与这种情况,比如说task1中有a,b,c三个activity,此时在c中启动d的话,如果在androidmanifest.xml文件中给d添加了affinity的值和task中的不一样的话,则会在新标记的affinity所存在的task中压入这个activity。如果是默认的或者指定的affinity和task一样的话,就和标准模式一样了启动一个新的activity.

flag_activity_single_top这个flag就相当于启动模式中的singletop,例如:原来栈中结构是a b c d,在d中启动d,栈中的情况还是a,b,c,d。

flag_activity_clear_top这个flag就相当于启动模式中的singletask,这种flag启动的activity会把要启动的activity之上的activity全部弹出栈空间。例如:原来栈中的结构是a b c d ,从d中跳转到b,栈中的结构就变为了a b了。

flag_activity_brought_to_front

这个网上很多人是这样写的。如果activity在task存在,拿到最顶端,不会启动新的activity。这个有可能会误导大家! 他这个flag其实是这个意思!比如说我现在有a,在a中启动b,此时在a中intent中加上这个标记。此时b就是以flag_activity_brought_to_front方式启动,此时在b中再启动c,d(正常启动c,d),如果这个时候在d中再启动b,这个时候最后的栈的情况是 a,c,d,b。如果在a,b,c,d正常启动的话,不管b有没有用flag_activity_brought_to_front启动,此时在d中启动b的话,还是会变成a,c,d,b的。

flag_activity_no_user_action

onuserleavehint()作为activity周期的一部分,它在activity因为用户要跳转到别的activity而要退到background时使用。比如,在用户按下home键,它将被调用。比如有电话进来(不属于用户的选择),它就不会被调用。
那么系统如何区分让当前activity退到background时使用是用户的选择?

它是根据促使当前activity退到background的那个新启动的activity的intent里是否有flag_activity_no_user_action来确定的。
注意:调用finish()使该activity销毁时不会调用该函数

flag_activity_no_history

意思就是说用这个flag启动的activity,一旦退出,它不会存在于栈中,比如原来是a,b,c这个时候再c中以这个flag启动d的,d再启动e,这个时候栈中情况为a,b,c,e。

activity相关属性taskaffinity

activity 中的 android:taskaffinity 这个属性介绍:
activity为task拥有的一个affinity。拥有相同的affinity的activity理论上属于相同的task(在用户的角度是相同的“应用程序”)。task的affinity是由它的根activity决定的。 

affinity决定两件事情——activity重新宿主的task(参考allowtaskreparenting特性)和使用flag_activity_new_task标志启动的activity宿主的task。

默认情况,一个应用程序中的所有activity都拥有相同的affinity。捏可以设定这个特性来重组它们,甚至可以把不同应用程序中定义的activity放置到相同的task中。为了明确activity不宿主特定的task,设定该特性为空的字符串。

如果这个特性没有设置,activity将从应用程序的设定那里继承下来(参考<application>元素的taskaffinity特性)。应用程序默认的affinity的名字是<manifest>元素中设定的package名。