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

澳门新葡亰手机版 1

FLAG_ACTIVITY_NO_HISTORY

意思就是说用这个FLAG启动的Activity,一旦退出,它不会存在于栈中,比如原来是A,B,C这个时候再C中以这个FLAG启动D的,D再启动E,这个时候栈中情况为A,B,C,E。

Activity任务栈和四种启动模式

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

首先要注册一个Activity清单配置
  <application android:allowbackup="false"   
    android:icon="@mipmap/ic_launcher" 
    android:label="@string/app_name"    
    android:roundicon="@mipmap/ic_launcher_round" 
    android:supportsrtl="true" 
    android:theme="@style/AppTheme">
    <activity android:name=".MainActivity">
       <intent-filter>
          <action android:name="android.intent.action.MAIN"/>
        <category  android:name="android.intent.category.LAUNCHER"/>
    </intent-filter>
    </activity>
<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>
下面我们来一起看看Android官方文档上提供的Activity的生命周期图:

澳门新葡亰手机版 1

Activity生命周期图

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位于栈顶)

个别参数解释

1.allowBackup:是否允许备份应用的数据,当备份数据的时候,它的数据会被备份下来。如果设为false,那么绝对不会备份应用的数据,即使是备份整个系统,默认是true。

2.icon&roundIcon:现在Android新建项目后会自动设置两个图标,icon和roundicon,一个是普通图标,一个是圆形图标。

3.supportsRtl:声明你的application是否愿意支持从右到左(原来RTL就是right-to-left
的缩写…)的布局,如果设置为true,targetSdkVersion设置为17或更高,各种RTL的API将被激活,系统使用您的应用程序可以显示RTL布局。如果targetSdkVersion设置为16或更低的设置为false,RTL的API将被忽略或没有影响您的应用程序将具有相同的行为无论对用户现场的选择相关的布局方向(你的布局会从左至右),此属性的默认值是false。

4.activity :注册的Activity

5.intent-filter:过滤器intent-filter 设置action
=”android.intent.action.MAIN”、category
=”android.intent.category.LAUNCHER”
,意思就是设置MainActivity为app的入口函数。

FLAG_ACTIVITY_CLEAR_TOP

这个FLAG就相当于启动模式中的SingleTask,这种FLAG启动的Activity会把要启动的Activity之上的Activity全部弹出栈空间。例如:原来栈中的结构是A
B C D ,从D中跳转到B,栈中的结构就变为了A B了。

Activity的启动

1、显示启动
何为显示启动,就是在创建Intent的时指定要启动的activity的类。所以前提是我们已经知道Activity的类名称,这就运用在我们在开发app中进行activity的跳转。

Intent intent = new Intent(MainActivity.this,SecondActivity.class);
startActivity(intent);

2、隐式启动
android系统给我们提供了许多服务,如打电话、发短信。但是在我们的应用中我们不知道具体的activity类名称,此时我们就需要用到隐式的activity启动方法。

//打电话
Intent intent = new Intent(Intent.ACTION_DIAL, Uri.parse("tel:555-2368"));
startActivity(intent);

//发短信
Intent intent=new Intent();
intent.setAction("android.intent.action.SEND");
intent.setData(Uri.parse("mms:110"));
intent.addCategory(Intent.CATEGORY_DEFAULT);
startActivity(intent);

//打开网页
Intent intent=new Intent();
intent.setAction(Intent.ACTION_VIEW);
intent.setData(Uri.parse("http://www.baidu.com"));
startActivity(intent);

这个时候,ActivityA启动ActivityB,B没有完全遮挡A,ActivityB的生命周期跟刚才一样,但是ActivityA并没有执行onStop()

Activity优先级
  1. 前台Activity——正在和用户交互的Activity,优先级最高

  2. 可见但非前台Activity——Activity中弹出的对话框导致Activity可见但无法交互

  3. 后台Activity——已经被暂停的Activity,优先级最低

Intent.FLAG_ACTIVITY_NEW_TASK (默认)

默认的跳转类型,它会重新创建一个新的Activity,不过与这种情况,比如说Task1中有A,B,C三个Activity,此时在C中启动D的话,如果在AndroidManifest.xml文件中给D添加了Affinity的值和Task中的不一样的话,则会在新标记的Affinity所存在的Task中压入这个Activity。如果是默认的或者指定的Affinity和Task一样的话,就和标准模式一样了启动一个新的Activity.

onSaveInstanceState何时调用

在activity被杀掉之前调用保存每个实例的状态,以保证该状态可以在onCreate(Bundle)或者onRestoreInstanceState(Bundle)
(传入的Bundle参数是由onSaveInstanceState封装好的)中恢复。这个方法在一个activity被杀死前调用,当该activity在将来某个时刻回来时可以恢复其先前状态。例如,如果activity
B启用后位于activity A的前端,在某个时刻activity
A因为系统回收资源的问题要被杀掉,A通过onSaveInstanceState将有机会保存其用户界面状态,使得将来用户返回到activity
A时能通过onCreate(Bundle)或者onRestoreInstanceState(Bundle)恢复界面的状态。

不要将这个方法和activity生命周期回调如onPause()或onStop()搞混淆了,onPause()在activtiy被放置到背景或者自行销毁时总会被调用,onStop()在activity被销毁时被调用。一个会调用onPause()和onStop(),但不触发onSaveInstanceState的例子是当用户从activity
B返回到activity
A时:没有必要调用B的onSaveInstanceState(Bundle),此时的B实例永远不会被恢复,因此系统会避免调用它。一个调用onPause()但不调用onSaveInstanceState的例子是当activity
B启动并处在activity
A的前端:如果在B的整个生命周期里A的用户界面状态都没有被破坏的话,系统是不会调用activity
A的onSaveInstanceState(Bundle)的。

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

方法介绍
  • onCreate()方法
    这个方法我们必须实现,当我们创建一个activity的时候,系统会调用这个方法。重要的是,我们必须通过setContentView()来设定activity的显示视图。(不可见)

  • onStart()方法
    在我们创建了视图之后调用,在向用户展示之前调用。然后调用onResume方法。(不可见)

  • onResume()方法:
    onResume方法是activity进行可见状态,能够与用户进行交互。(可见可用)

  • onPause()方法
    当我们离开这个activity时候系统调用这个方法。注意:它不意味着activity被销毁(destroy)。暂停状态,记得小时候打游戏,按暂停,游戏界面就会停止不动,属于可见状态,但是不能用,其实原理基本类似。(可见但不可用)

  • onRestart:Activity的重启,由不可见变为可见

  • onStop()方法
    停止状态,当一个activity被另一个activity完全覆盖的时候,它仍然保留着信息,但是已经对用户不可见。(不可见)

  • onDestroy()方法
    此时activity已经被销毁,activity至此生命周期完全结束。(销毁)

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的。

Intent Flag启动模式

intent 在跳转页面的时候可以设置intent.setFlags()

  • FLAG_ACTIVITY_CLEAR_TOP:例 如现在的栈情况为:A B C D
    。D此时通过intent跳转到B,如果这个intent添加FLAG_ACTIVITY_CLEAR_TOP标记,则栈情况变为:A
    B。如果没有添加这个标记,则栈情况将会变成:A B C D
    B。也就是说,如果添加了FLAG_ACTIVITY_CLEAR_TOP标记,并且目标Activity在栈中已经存在,则将会把位于该目标
    activity之上的activity从栈中弹出销毁。这跟上面把B的Launch
    mode设置成singleTask类似。简而言之,跳转到的activity若已在栈中存在,则将其上的activity都销掉。

  • FLAG_ACTIVITY_NEW_TASK:例 如现在栈1的情况是:A B
    C。C通过intent跳转到D,并且这个intent添加了FLAG_ACTIVITY_NEW_TASK标记,如果D这个Activity在
    Manifest.xml中的声明中添加了Task
    affinity,系统首先会查找有没有和D的Task
    affinity相同的task栈存在,如果有存在,将D压入那个栈,如果不存在则会新建一个D的affinity的栈将其压入。如果D的Task
    affinity默认没有设置,则会把其压入栈1,变成:A B C
    D,这样就和不加FLAG_ACTIVITY_NEW_TASK标记效果是一样的了。注意如果试图从非activity的非正常途径启动一个
    activity(例见下文“intent.setFlags()方法中参数的用例”),比如从一个service中启动一个activity,则intent比如要添加FLAG_ACTIVITY_NEW_TASK标记(编者按:activity要存在于activity的栈中,而非activity的途径启动activity时必然不存在一个activity的栈,所以要新起一个栈装入启动的activity)。简而言之,跳转到的activity根据情况,可能压在一个新建的栈中。

  • FLAG_ACTIVITY_NO_HISTORY: 例如现在栈情况为:A B
    C。C通过intent跳转到D,这个intent添加FLAG_ACTIVITY_澳门新葡亰手机版,NO_HISTORY标志,则此时界面显示D的内容,但是它并不会压
    入栈中。如果按返回键,返回到C,栈的情况还是:A B
    C。如果此时D中又跳转到E,栈的情况变为:A B C
    E,此时按返回键会回到C,因为D根本就没有被压入栈中。简而言之,跳转到的activity不压在栈中。

  • FLAG_ACTIVITY_SINGLE_TOP:和Activity的Launch
    mode的singleTop类似。如果某个intent添加了这个标志,并且这个intent的目标activity就是栈顶的activity,那么将不会新建一个实例压入栈中。简而言之,目标activity已在栈顶则跳转过去,不在栈顶则在栈顶新建activity。

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

有回调的跳转
/*
*ActivityA跳ActivityB
*/
Intent intnt = new Intent(this,ActivityB.class);
startActivityForResult(int reqCode, Intent intent): 带回调启动Activity

/*
*ActivityB销毁 返回ActivityA
/
 setResult(int resultCode, Intent data): 设置要返回的结果
 finish(): 结束当前Activity

/*
*ActivityA 接收之后ActivityB返回的参数
/
onActivityResult(int reqCode, int resultCode, Intent data): 回调方法
通过data获取返回的数据 进行操作

Intent Flags

Flags:
表示Intent的标志位,常用于Activity的场景中,它和Activity的启动模式有着密切的联系。
下面列举的是和本文主题相关的Flags属性:

测试Activity的生命周期:
  1. 界面从“死亡”–>“运行”
    构造器–>onCreate()—>onStart()–>onResume()

  2. 界面从“运行”–>“死亡”
    onPause()–>onStop()–>onDestroy()

  3. 界面从“运行”–>“停止”
    onPause()–>onStop()

  4. 界面从“停止” –>“运行”
    onRestart()–>onStart()–>onResume()

  5. 界面从“运行”–>“暂停”
    onPause()

  6. 界面从“暂停” –>“运行”
    onResume()

在实际的开发中,我们根据activity的生命周期来实现我们的逻辑处理。通常在开发中,在onCreate()方法中进行一些变量的初始化工作,包括变量的初始化、控件的初始化、控件设置监听等。当一个activity由于失去焦点时再次重新获取焦点调用onResume方法。在onResume()方法中我们可以处理一些比如界面的更新操作。

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

每个应用会有一个Activity任务栈,存放已启动的Activity
  • standard:默认的启动模式,该模式下会生成一个新的Activity,同时将该Activity实例压入到栈中(不管该Activity是否已经存在在Task栈中,都是采用new操作)。例如:
    栈中顺序是A B C D ,此时D通过Intent跳转到A,那么栈中结构就变成 A B C
    D A,点击返回按钮的 显示顺序是 D C B A,依次摧毁。

  • singleTop:在singleTop模式下,如果当前Activity
    D位于栈顶,此时通过Intent跳转到它本身的Activity(即D),那么不会重新创建一个新的D实例(走onNewIntent()),所以栈中的结构依旧为A
    B C
    D,如果跳转到B,那么由于B不处于栈顶,所以会新建一个B实例并压入到栈中,结构就变成了A
    B C D B。应用实例:三条推送,点进去都是一个activity。

  • singleTask:在singleTask模式下,Task栈中只能有一个对应Activity的实例。例如:现在栈的结构为A
    B C
    D,此时D通过Intent跳转到B(走onNewIntent()),则栈的结构变成了:A
    B。其中的C和D被栈弹出销毁了,也就是说位于B之上的实例都被销毁了。如果系统已经存在一个实例,系统就会将请求发送到这个实例上,但这个时候,系统就不会再调用通常情况下我们处理请求数据的onCreate方法,而是调用onNewIntent方法。通常应用于首页,首页肯定得在栈底部,也只能在栈底部。

  • singleInstance:singleInstance模式下会将打开的Activity压入一个新建的任务栈中。例如:Task栈1中结构为:A
    B
    C,C通过Intent跳转到了D(D的启动模式为singleInstance),那么则会新建一个Task
    栈2,栈1中结构依旧为A B
    C,栈2中结构为D,此时屏幕中显示D,之后D通过Intent跳转到D,栈2中不会压入新的D,所以2个栈中的情况没发生改变。如果D跳转到了C,那么就会根据C对应的启动模式在栈1中进行对应的操作,C如果为standard,那么D跳转到C,栈1的结构为A
    B C C,此时点击返回按钮,还是在C,栈1的结构变为A B C,而不会回到D。

ActivityA 的生命周期onPause()->onStop(),

Activity简介

Activity是Android一个非常重要的用户接口(四大组件之一),是可见的,主要是用户和应用程序之间进行交互的接口。在每个Activity中都可以放很多控件,所以也可以把Activity看作控件的容器。它负责了我们的界面显示,实际开发中我们通过setContentView(R.layout.id)设置界面显示的视图。在Android的项目结构设计中,Activity就相当于MVC设计模式中的View层。在Android的四大组件设计中,为了方便开发者进行开发使用,Android的开发者对四大组件通过生命周期进行管理,我们只需要继承Activity进行重写这些生命周期来管理和合理使用Activity。

ActivityA启动ActivityB:

注意点
  • 其中onCreate和onDestory为完整的生命周期,onStart和onStop为可见生命周期,onResume和onPause为前台生命周期。

  • 当用户打开新的Activity或切换回到桌面的时候,回调为onPause->onStop,但是若Activity采用的为透明主题,则不会回调onStop。

  • 一般情况下,Activity有不可见变为可见,onRestart才会调用。

  • onStart和onStop控制Activity在可见和不可见的状态之间转换,onResume和onPause控制Activity在前台或非前台之间转换。

  • 当由Activity A ->Activity
    B时,回调的顺序为onPause(A)->onCreate(B)->onStart(B)->onStop(A),因此不可以在onPause上做重量级操作。

  • 如果应用长时间处于stopped状态并且此时系统内存极为紧张的时候,系统就会回收Activity,此时系统在回收之前会回调onSaveInstanceState方法来保存应用的数据Bundle。当该Activity重新创建的时候,保存的Bundle数据就会传递到onRestoreSaveInstanceState方法和onCreate方法中,这就是onCreate方法中Bundle
    savedInstanceState参数的来源(onRestoreInstanceState的bundle参数也会传递到onCreate方法中,你也可以选择在onCreate方法中做数据还原)。

ActivityA的生命周期了onRestart()->onStart()->onResume()

FLAG_ACTIVITY_NO_USER_ACTION

onUserLeaveHint()作为activity周期的一部分,它在activity因为用户要跳转到别的activity而要退到background时使用。比如,在用户按下Home键,它将被调用。比如有电话进来(不属于用户的选择),它就不会被调用。

那么系统如何区分让当前activity退到background时使用是用户的选择?

它是根据促使当前activity退到background的那个新启动的Activity的Intent里是否有FLAG_ACTIVITY_NO_USER_ACTION来确定的。

注意:调用finish()使该activity销毁时不会调用该函数

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名。

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