Activity

来源:互联网 发布:mac无法建立安全连接 编辑:程序博客网 时间:2024/05/18 17:56

基础概念

什么是 Activity?

四大组件之一,通常一个用户交互界面对应一个 activity。activity 是Context 的子类,同时实现了 window.callback和 keyevent.callback, 可以处理与窗体用户交互的事件。

常见的 Activity 类型有 FragmentActivitiy,ListActivity,TabAcitivty 等。 如果界面有共同的特点或者功能的时候,还会自己定义一个 BaseActivity。

Activity 生命周期


两两对应:onCreate 创建与 onDestroy 销毁;onStart 可见与 onStop 不可见;onResume 可编辑(即焦点)与 onPause;

 

什么情况下Activity走了onCreat(),而不走onStart();

当onCreate中发生Crash的时候。

何时调用onRestart

在 Activity 被 onStop 后,但是没有被 onDestroy,在再次启动此 Activity 时就调用 onRestart(而不再调用 onCreate)方法;如果被 onDestroy 了,则是调用 onCreate 方法。

onPause vs onStop

(a) 只要activity还可见,就不会调用onStop。所以我们可以知道onStop调用时机是:当一个activity对用户已经不可见的时候就会调用。
(b) 官方说明:onStop可能永远不会被调用:当处于低内存状态下,系统没有足够的内存保持你的activity的处理运行在activity的onPause调用之后。
(c) 从(b)知道onStop在低内存情况下不会被调用,但是:onPause一定会被调用

onResume

对于你的activity来说,onResume调用后就可以和用户交互,这是很好的地方去开始动画,打开互斥访问设备元件(例如:照相机),etc.
但是有一点我们必须认清:onResume不是最好的指向标说明你的activity对于用户是可见的,例如系统的窗口可能在你的activity前面。所以应该用:onWindowFocusChanged来知道我们的activity是否对用户可见。

onWindowFocusChanged

当前activity的窗口获得或失去焦点的时候会调用。(activity是否对用户可见)

大多数情况下只要调用了onResume 就会调用 onWindowFocusChanged,也有例外,比如下拉系统菜单的时候只会调用onWindowFocusChanged。
应用:我们在下拉菜单中改变了网络的状态(开启或者关闭),我们这时候就不能在onResume()中处理更新网络状态,而应该将更新网络状态放到onWindowFocusChanged中处理。

**官方解释**:当前activity的窗口获得或失去焦点的时候会调用。这个函数是最好的方向标对于activity是否对用户可见,它默认的实现是清除键跟踪状态,所以应该总是被调用。它也提供了全局的焦点状态,它的管理是独立于activity生命周期的。当焦点改变时一般都伴随着生命周期的改变,你不应该依赖onWindowFocusChanged 调用和其他生命周期的方法(例如onResume) 的先后顺序,来处理我们要做的事情。通常的规则是,当一个activity被唤醒,那么就拥有窗口焦点。除非这个窗口已经显示了对话框或者其他弹出框抢占焦点,这个窗口只有等到这些对话框关闭后,才能获取焦点,同理,当系统显示系统级的窗口,系统级的窗口会临时的获取窗口输入焦点同时不会暂停前景 activity。

onStart()和onResume()有什么区别?

在onStart()中视图不可见,在onResume()中视图可见;onStart()属于可见进程,onResume()属于前台进程;

横竖屏切换时 Activity 的生命周期

此时的生命周期跟清单文件里的配置有关系。
1、不设置 Activity 的 android:configChanges 时,切屏会重新调用各个生命周期 默认首先销毁当前 activity,然后重新加载。
如下图,当横竖屏切换时先执行 onPause/onStop 方法



2、设置 Activity 的 android:configChanges="orientation|screenSize"时(两个都要设置),切屏不会重新调用各个生命周期,只会执行 onConfigurationChanged 方法。
注意:
1.如果<activity>配置了android:screenOrientation属性,则会使android:configChanges="orientation"失效。
2.模拟器与真机差别很大:模拟器中如果不配置android:configChanges属性或配置值为orientation,切到横屏执行一次销毁->重建,切到竖屏执行两次。真机均为一次。模拟其中如果配置android:configChanges="orientation|keyboardHidden",切竖屏执行一次onConfigurationChanged,切竖屏执行两次。真机均为一次。

两个Activity之间跳转的生命周期过程

一般情况下比如说有两个 activity,分别叫 A,B,当在 A 里面激活 B 组件的时候, A 会调用 onPause()方法,然后 B 调 用 onCreate() ,onStart(), onResume()。
这个时候 B 覆盖了窗体, A 会调用 onStop()方法. 如果 B 是个透明的,或者是对话框的样式, 就不会调用 A 的onStop()方法

Activity 的状态

a) foreground activity
b) visible activity
c) background activity
d) empty process

如何保存 Activity 状态

Activity 的状态通常情况下系统会自动保存
一般来说, 调用 onPause()和 onStop()方法后的 activity 实例仍然存在于内存中, activity 的所有信息和状态数据不会消失, 当 activity 重新回到前台之后, 所有的改变都会得到保留。
但是当系统内存不足时, 调用 onPause()和 onStop()方法后的 activity 可能会被系统摧毁, 此时内存中就不会存有该 activity 的实例对象了。如果之后这个 activity 重新回到前台, 之前所作的改变就会消失。

解决方案:覆写 onSaveInstanceState()方法。
onSaveInstanceState()方法接受一个 Bundle 类型的参数, 开发者可以 将状态数据存储到这个 Bundle 对象中, 这样即使 activity 被系统摧毁, 当用户重新启动这个 activity 而调用它的 onCreate()方法时, 上述的 Bundle 对象会作为实参传递给 onCreate()方法, 开发者可以从 Bundle 对象中取出保存的 数据, 然后利用这些数据将 activity 恢复到被摧毁之前的状态。

需要注意的是, onSaveInstanceState()方法并不是一定会被调用的, 因为有些场景是不需要保存状态数据的。比如用户按下 BACK 键退出 activity 时, 用户显然想要关闭这个 activity, 此时是没有必要保存数据以供下次恢复的, 也就是 onSaveInstanceState()方法不会被调用。
如果调用 onSaveInstanceState()方法, 调用将发生在 onPause()或onStop()方法之前

@Overrideprotected void onSaveInstanceState(Bundle outState) {// TODO Auto-generated method stubsuper.onSaveInstanceState(outState);}

各种情况下函数调用过程

第一次进入ActivityA:

A | onCreate
A | onStart
A | onResume
A | onWindowFocusChanged | hasFocus:true

下拉系统菜单(已开启程序,从屏幕上往下拉)

A | onWindowFocusChanged | hasFocus:false

收回系统下拉菜单(已开启程序,且下拉菜单已显示)

A | onWindowFocusChanged | hasFocus:true

从ActivityA中退出:

A | onPause
A | onWindowFocusChanged | hasFocus:false
A | onStop
A | onDestory

ActivityA启动ActivityB(普通Activity):

A | onWindowFocusChanged | hasFocus:false
A | onPause
B | onCreate
B | onStart
B | onResume
B | onWindowFocusChanged | hasFocus:true
A | onSaveInstanceState | param: 1
A | onStop

ActivityA启动ActivityB(对话框Activity):

A | onWindowFocusChanged | hasFocus:false
A | onPause
B | onCreate
B | onStart
B | onResume
B | onWindowFocusChanged | hasFocus:true

从AcitivityB(普通Activity)返回到ActivityA:

B | onPause
A | onRestart
A | onStart
A | onResume
A | onWindowFocusChanged | hasFocus:true
B | onWindowFocusChanged | hasFocus:false
B | onStop
B | onDestory

从ActivityB(对话框Activity)返回到ActivityA:

B | onPause
A | onResume
A | onWindowFocusChanged | hasFocus:true
B | onWindowFocusChanged | hasFocus:false
B | onStop
B | onDestory

手机黑屏时:

A | onPause
A | onSaveInstanceState | param: 1
A | onStop
A | onWindowFocusChanged | hasFocus:false

手机亮屏时:

A | onWindowFocusChanged | hasFocus:true
A | onRestart
A | onStart
A | onResume

按home键(已启动ActivityA)

A | onPause
A | onWindowFocusChanged | hasFocus:false
A | onSaveInstanceState | param: 1
A | onStop

多任务切回程序(开启程序,home键切换程序到后台)

A | onRestart
A | onStart
A | onResume
A | onWindowFocusChanged | hasFocus:true

点击应用图标重启程序(开启程序,home键切换到后台)

A | onRestart
A | onStart
A | onResume
A | onWindowFocusChanged | hasFocus:true

点击back键(已开启程序,back键未自己处理)

A | onPause
A | onWindowFocusChanged | hasFocus:false
A | onStop
A | onDestory

点击多任务键(已开启程序)

A | onWindowFocusChanged | hasFocus:false
A | onPause
A | onSaveInstanceState | param: 1
A | onStop

切回程序(已开启程序,且已点击多任务键)

A | onRestart
A | onStart
A | onResume
A | onWindowFocusChanged | hasFocus:true

横竖屏切换(未配置android:configChanges)

A | onPause
A | onSaveInstanceState | param: 1
A | onStop
A | onDestory
A | onCreate
A | onStart
A | onRestoreInstanceState | param: 1
A | onResume
A | onWindowFocusChanged | hasFocus:true

横竖屏切换(配置android:configChanges="orientation")

竖切横
A | onConfigurationChanged | newConfig:{1.0 460mcc3mnc [zh_CN_#Hans] ldltr sw360dp w592dp h336dp 320dpi nrml land finger -keyb/v/h -nav/h suim:1 s.22}
A | onPause
A | onSaveInstanceState | param: 1
A | onStop
A | onDestory
A | onCreate
A | onStart
A | onRestoreInstanceState | param: 1
A | onResume
A | onWindowFocusChanged | hasFocus:true
横切竖
A | onConfigurationChanged | newConfig:{1.0 460mcc3mnc [zh_CN_#Hans] ldltr sw360dp w360dp h580dp 320dpi nrml port finger -keyb/v/h -nav/h suim:1 s.23}

横竖屏切换(配置android:configChanges="orientation|scre

竖切横
A | onConfigurationChanged | newConfig:{1.15 460mcc3mnc [zh_CN_#Hans] ldltr sw360dp w592dp h336dp 320dpi nrml land finger -keyb/v/h -nav/h suim:1 s.46}
横切竖
A | onConfigurationChanged | newConfig:{1.15 460mcc3mnc [zh_CN_#Hans] ldltr sw360dp w360dp h580dp 320dpi nrml port finger -keyb/v/h -nav/h suim:1 s.47}

ActivityA启动ActivityB,再从ActivityB回到ActivityA,此时ActivityB的onDestory先调用还是ActivityA的onResume先调用?

ActivityA的onResume()先调用,ActivityB的onDestory后调用。

 

Activity 启动模式

启动模式(launchMode)在多个 Activity 跳转的过程中扮演着重要的角色,它可以决定是否生成新的 Activity 实例,是否重用已存在的 Activity 实例,是否和其他 Activity 实例公用一个 task 里。

task 是一个具有栈结构的对象,一个 task 可以管理多个 Activity,启动一个应用,也就创建一个与之对应的 task。

Activity 一共有以下四种 launchMode:
1.standard
2.singleTop
3.singleTask
4.singleInstance
可以在 AndroidManifest.xml 配置<activity>的 android:launchMode 属性为以上四种之一即可。

1 standard

默认启动模式,每次激活Activity时都会创建Activity,并放入任务栈中。

standard 模式是默认的启动模式,不用为<activity>配置 android:launchMode 属性即可,当然也可以指定值 为 standard。

原理如下:


如图所示,每次跳转系统都会在 task 中生成一个新的 FirstActivity 实例,并且放于栈结构的顶部,当我们按下后退键时,才能看到原来的 FirstActivity 实例。

2 singleTop

如果在任务的栈顶正好存在该Activity的实例, 就重用该实例,否者就会创建新的实例并放入栈顶(即使栈中已经存在该Activity实例,只要不在栈顶,都会创建实例)。
原理:


3 singleTask

如果在栈中已经有该Activity的实例,就重用该实例(会调用实例的onNewIntent())。重用时,会让该实例回到栈顶,因此在它上面的实例将会被移除栈。如果栈中不存在该实例,将会创建新的实例放入栈中。
原理:



在图中的下半部分是 SecondActivity 跳转到 FirstActivity 后的栈结构变化的结果,我们注意到,SecondActivity消失了,没错,在这个跳转过程中系统发现有存在的 FirstActivity 实例,于是不再生成新的实例,而是将 FirstActivity之上的 Activity 实例统统出栈,将 FirstActivity 变为栈顶对象,显示到幕前。

4 singleInstance

在一个新栈中创建该Activity实例,并让多个应用共享改栈中的该Activity实例。一旦该模式的Activity的实例存在于某个栈中,任何应用再激活改Activity时都会重用该栈中的实例,其效果相当于多个应用程序共享一个应用,不管谁激活该Activity都会进入同一个应用中

我们修改 FirstActivity 的 launchMode="standard",SecondActivity 的launchMode="singleInstance",由于涉及到了多个栈结构,我们需要在每个 Activity 中显示当前栈结构的 id,所以我们为每个 Activity 添加如下代码:

textView.setText(this.toString());taskIdView.setText("current task id: " + this.getTaskId());

然后我们再演示一下这个流程:



我们发现这两个 Activity 实例分别被放置在不同的栈结构中,关于 singleInstance 的原理图如下



我们看到从 FirstActivity 跳转到 SecondActivity 时,重新启用了一个新的栈结构,来放置 SecondActivity 实例,然后按下后退键,再次回到原始栈结构;图中下半部分显示的在 SecondActivity 中再次跳转到 FirstActivity,这个时候系统会在原始栈结构中生成一个 FirstActivity 实例,然后回退两次,注意,并没有退出,而是回到了 SecondActivity,

为什么呢?是因为从 SecondActivity 跳转到 FirstActivity 的时候,我们的起点变成了 SecondActivity 实例所在的栈结构,这样一来,我们需要“回归”到这个栈结构。

如果我们修改 FirstActivity 的 launchMode 值为 singleTop、singleTask、singleInstance 中的任意一个,流程将会如图所示:



singleInstance 启动模式可能是最复杂的一种模式,为了帮助大家理解,我举一个例子,假如我们有一个 share 应用, 其中的 ShareActivity 是入口 Activity,也是可供其他应用调用的 Activity,我们把这个 Activity 的启动模式设置为 singleInstance,然后在其他应用中调用。我们编辑 ShareActivity 的配置:

        <activity            android:name=".ShareActivity"            android:launchMode="singleInstance">            <intent-filter>                <action android:name="android.intent.action.MAIN" />                <category android:name="android.intent.category.LAUNCHER" />            </intent-filter>            <intent-filter>                <action android:name="android.intent.action.SINGLE_INSTANCE_SHARE" />                <category android:name="android.intent.category.DEFAULT" />            </intent-filter>        </activity>

然后我们在其他应用中这样启动该 Activity:

Intent intent = new Intent("android.intent.action.SINGLE_INSTANCE_SHARE");startActivity(intent);

当我们打开 ShareActivity 后再按后退键回到原来界面时,ShareActivity 做为一个独立的个体存在,如果这时我 们打开 share 应用,无需创建新的 ShareActivity 实例即可看到结果,因为系统会自动查找,存在则直接利用。大家 可以在 ShareActivity 中打印一下 taskId,看看效果。关于这个过程,原理图如下:


onNewIntent

重复启动同一个Activity实例时会调用onNewIntent()
Activity第一启动的时候执行onCreate()---->onStart()---->onResume()等后续生命周期函数,也就时说第一次启动Activity并不会执行到onNewIntent(). 而后面如果再有想启动该Activity的时候,那就是执行onNewIntent()---->onResart()--->onStart()----->onResume()。如果android系统由于内存不足把已存在Activity释放掉了,那么再次调用的时候会重新启动Activity即执行onCreate()---->onStart()---->onResume()等。

当调用到onNewIntent(intent)的时候,需要在onNewIntent() 中使用setIntent(intent)赋值给Activity的Intent.否则,后续的getIntent()都是得到老的Intent。

一个启动模式为 singleTop 的 activity,如果再试图启动会怎样?

面试官想问的是onNewIntent()

Activity 有一个 onNewIntent(Intent intent)回调方法,该方法我们几乎很少使用,导致已经将其忽略掉。该方法的官方解释如下:
This is called for activities that set launchMode to "singleTop" in their package, or if a client used
the Intent.FLAG_ACTIVITY_SINGLE_TOP flag when calling startActivity. In either case, when the activity is re-launched while at the top of the activity stack instead of a new instance of the activity being started, onNewIntent() will be called on the existing instance with the Intent that was used to re-launch it.
An activity will always be paused before receiving a new intent, so you can count on onResume being called after this method.
Note that getIntent still returns the original Intent. You can use setIntent to update it to this new
Intent.

上文大概意思如下:

该方法被启动模式设置为“singleTop”的 Activity 回调,或者当通过设置 Intent.FLAG_ACTIVITY_SINGLE_TOP 的 Intent 启动 Activity 时被回调。在任何情况下,只要当栈顶的 Activity 被重新启动时没有重新创建一个新的 Activity 实例而是依然使用该 Activity 对象,那么 onNewIntent(Intent)方法就会被回调。
当一个 Activity 接收到新 Intent 的时候会处于暂停状态,因此你可以统计到 onResume()方法会被再次执行,当 然这个执行是在 onNewIntent 之后的。
注意:如果我们在 Activity 中调用了 getIntent()方法,那么返回的 Intent 对象还是老的 Intent(也就是第一 次启动该 Activity 时的传入的 Intent 对象),但是如果想让 getIntent()返回最新的 Intent,那么我们可以通过 setIntent(Intent)方法设置。

实际演示:

启动方式启动Activity执行函数task中ActivityStandardStandardActivity@96267d3onCreate  onStart  onResume TaskId: 187StandardActivity@96267d3 TaskId【187】SingleInstanceSingleInstanceActivity@a2e46b7onCreate  onStart  onResume TaskId: 188StandardActivity@96267d3【187】
SingleInstanceActivity@a2e46b7【188】SingleInstanceSingleInstanceActivity@a2e46b7onNewIntent  onResume TaskId: 188StandardActivity@96267d3【187】
SingleInstanceActivity@a2e46b7【188】SingleTaskSingleTaskActivity@e0f0b0aonCreate  onStart  onResume TaskId: 187SingleTaskActivity@e0f0b0a
StandardActivity@96267d3【187】
SingleInstanceActivity@a2e46b7【188】SingleTaskSingleTaskActivity@e0f0b0aonNewIntent  onResume TaskId: 187SingleTaskActivity@e0f0b0a
StandardActivity@96267d3【187】
SingleInstanceActivity@a2e46b7【188】SingleTopSingleTopActivity@21bfd59onCreate  onStart  onResume TaskId: 187SingleTopActivity@21bfd59
SingleTaskActivity@e0f0b0a
StandardActivity@96267d3【187】
SingleInstanceActivity@a2e46b7【188】SingleTopSingleTopActivity@21bfd59onNewIntent  onResume TaskId: 187SingleTopActivity@21bfd59
SingleTaskActivity@e0f0b0a
StandardActivity@96267d3【187】
SingleInstanceActivity@a2e46b7【188】StandardStandardActivity@9f84b54onCreate  onStart  onResume TaskId: 187StandardActivity@9f84b54
SingleTopActivity@21bfd59
SingleTaskActivity@e0f0b0a
StandardActivity@96267d3【187】
SingleInstanceActivity@a2e46b7【188】StandardStandardActivity@a364129onCreate  onStart  onResume TaskId: 187StandardActivity@a364129
StandardActivity@9f84b54
SingleTopActivity@21bfd59
SingleTaskActivity@e0f0b0a
StandardActivity@96267d3【187】
SingleInstanceActivity@a2e46b7【188】SingleTopSingleTopActivity@a9c182aonCreate  onStart  onResume TaskId: 187SingleTopActivity@a9c182a
StandardActivity@a364129
StandardActivity@9f84b54
SingleTopActivity@21bfd59
SingleTaskActivity@e0f0b0a
StandardActivity@96267d3【187】
SingleInstanceActivity@a2e46b7【188】SingleTaskSingleTopActivity@21bfd59onDestroy StandardActivity@9f84b54onDestroy StandardActivity@a364129onDestroy SingleTaskActivity@e0f0b0aonNewIntent  onRestart  onStart  onResume TaskId: 187 SingleTopActivity@a9c182aonDestroySingleTaskActivity@e0f0b0a
StandardActivity@96267d3【187】
SingleInstanceActivity@a2e46b7【188】backStandardActivity@96267d3onRestart  onStart  onResume TaskId: 187 SingleTaskActivity@e0f0b0aonDestroySingleTaskActivity@e0f0b0a
StandardActivity@96267d3【187】
SingleInstanceActivity@a2e46b7【188】backStandardActivity@96267d3onDestroy SingleInstanceActivity@a2e46b7onRestart  onStart  onResume TaskId: 188SingleInstanceActivity@a2e46b7【188】

代码设置启动模式

Intent intent = new Intent(this, B.class); intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); startActivity(intent); 

Task就像一个容器,而Activity就相当与填充这个容器的东西,第一个东西(Activity)则会处于最下面,最后添加的东西(Activity)则会在最上面。从Task中取出东西(Activity)是从最顶端取出,也就是说最先取出的是最后添加的东西(Activity),以此类推,最后取出的是第一次添加的Activity,而Activity在Task中的顺序是可以控制的,在Activity跳转时用到Intent Flag可以设置新建activity的创建方式;

Intent常用标识:

FLAG_ACTIVITY_BROUGHT_TO_FRONT

这个标志一般不是由程序代码设置的,如在launchMode中设置singleTask模式时系统帮你设定。

FLAG_ACTIVITY_CLEAR_TOP

  +FLAG_ACTIVITY_SINGLE_TOP=singleTask:如果设置,并且这个Activity已经在当前的Task中运行,因此,不再是重新启动一个这个Activity的实例,而是在这个Activity上方的所有Activity都将关闭,然后这个Intent会作为一个新的Intent投递到老的Activity(现在位于顶端)中。
  例如,假设一个Task中包含这些Activity:A,B,C,D。如果D调用了startActivity(),并且包含一个指向Activity B的Intent,那么,C和D都将结束,然后B接收到这个Intent,因此,目前stack的状况是:A,B。
  上例中正在运行的Activity B既可以在onNewIntent()中接收到这个新的Intent,也可以把自己关闭然后重新启动来接收这个Intent。如果它的启动模式声明为 “multiple”(默认值),并且你没有在这个Intent中设置FLAG_ACTIVITY_SINGLE_TOP标志,那么它将关闭然后重新创建;对于其它的启动模式,或者在这个Intent中设置FLAG_ACTIVITY_SINGLE_TOP标志,都将把这个Intent投递到当前这个实例的onNewIntent()中。
  这个启动模式还可以与FLAG_ACTIVITY_NEW_TASK结合起来使用:用于启动一个Task中的根Activity,它会把那个Task中任何运行的实例带入前台,然后清除它直到根Activity。这非常有用,例如,当从Notification Manager处启动一个Activity。

FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET

API 21,被FLAG_ACTIVITY_NEW_DOCUMENT代替

  如果设置,这将在Task的Activity stack中设置一个还原点,当Task恢复时,需要清理Activity。也就是说,下一次Task带着 FLAG_ACTIVITY_RESET_TASK_IF_NEEDED标记进入前台时(经过测试发现,对于一个处于后台的应用,如果在launcher中点击应用,这个动作中含有FLAG_ACTIVITY_RESET_TASK_IF_NEEDED标记;长按Home键,然后点击最近记录,这个动作不含FLAG_ACTIVITY_RESET_TASK_IF_NEEDED标记),这个Activity和它之上的都将关闭,以至于用户不能再返回到它们,但是可以回到之前的Activity。
  这在你的程序有分割点的时候很有用。例如,一个e-mail应用程序可能有一个操作是查看一个附件,需要启动图片浏览Activity来显示。这个 Activity应该作为e-mail应用程序Task的一部分,因为这是用户在这个Task中触发的操作。然而,当用户离开这个Task,然后从主画面选择e-mail app,我们可能希望回到查看的会话中,但不是查看图片附件,因为这让人困惑。通过在启动图片浏览时设定这个标志,浏览及其它启动的Activity在下次用户返回到mail程序时都将全部清除。

FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS

  如果设置,新的Activity不会在最近启动的Activity的列表中保存。

FLAG_ACTIVITY_FORWARD_RESULT

  如果设置,并且这个Intent用于从一个存在的Activity启动一个新的Activity,那么,这个作为答复目标的Activity将会传到这个新的Activity中。这种方式下,新的Activity可以调用setResult(int),并且这个结果值将发送给那个作为答复目标的 Activity。

FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY

  这个标志一般不由应用程序代码设置,如果这个Activity是从历史记录里启动的(常按HOME键),那么,系统会帮你设定。

FLAG_ACTIVITY_MULTIPLE_TASK

  不要使用这个标志,除非你自己实现了应用程序启动器。与FLAG_ACTIVITY_NEW_TASK结合起来使用,可以禁用把已存的Task送入前台的行为。当设置时,新的Task总是会启动来处理Intent,而不管这是是否已经有一个Task可以处理相同的事情。
  由于默认的系统不包含图形Task管理功能,因此,你不应该使用这个标志,除非你提供给用户一种方式可以返回到已经启动的Task。
  如果FLAG_ACTIVITY_NEW_TASK标志没有设置,这个标志被忽略。

FLAG_ACTIVITY_NEW_TASK

  如果设置,这个Activity会成为历史stack中一个新Task的开始。一个Task(从启动它的Activity到下一个Task中的 Activity)定义了用户可以迁移的Activity原子组。Task可以移动到前台和后台;在某个特定Task中的所有Activity总是保持相同的次序。
  这个标志一般用于呈现“启动”类型的行为:它们提供用户一系列可以单独完成的事情,与启动它们的Activity完全无关。
  使用这个标志,如果正在启动的Activity的Task已经在运行的话,那么,新的Activity将不会启动;代替的,当前Task会简单的移入前台,保持栈中的状态不变,即栈中的顺序不变。
  这个标志不能用于调用方对已经启动的Activity请求结果。

设置此状态,记住以下原则,首先会查找是否存在和被启动的Activity具有相同的亲和性的任务栈(即taskAffinity,注意同一个应用程序中的activity的亲和性一样,所以下面的a情况会在同一个栈中,前面这句话有点拗口,请多读几遍),如果有,刚直接把这个栈整体移动到前台,并保持栈中的状态不变,即栈中的activity顺序不变,如果没有,则新建一个栈来存放被启动的activity

实例
a. 前提: Activity A和Activity B在同一个应用中。
  操作: Activity A启动开僻Task堆栈(堆栈状态: A), 在Activity A中启动Activity B, 启动Activity B的Intent的Flag设为FLAG_ACTIVITY_NEW_TASK
==>Activity B被压入Activity A所在堆栈(堆栈状态: AB)。
  原因: 默认情况下同一个应用中的所有Activity拥有相同的关系(taskAffinity)。

b. 前提: Activity A在名称为"TaskOne应用"的应用中, Activity C和Activity D在名称为"TaskTwo应用"的应用中。
  操作1: 在Launcher中单击"TaskOne应用"图标, Activity A启动开僻Task堆栈, 命名为TaskA(TaskA堆栈状态: A),在Activity A中启动Activity C, 启动Activity C的Intent的Flag设为FLAG_ACTIVITY_NEW_TASK,Android系统会为Activity C开僻一个新的Task, 命名为TaskB(TaskB堆栈状态: C), 长按Home键, 选择TaskA,Activity A回到前台, 再次启动Activity C(两种情况1。从桌面启动;2。从Activity A启动,两种情况一样), 这时TaskB回到前台, Activity C显示, 供用户使用, 即:
==>包含FLAG_ACTIVITY_NEW_TASK的Intent启动Activity的Task正在运行, 则不会为该Activity创建新的Task,而是将原有的Task返回到前台显示。

  操作2: 在Launcher中单击"TaskOne应用"图标, Activity A启动开僻Task堆栈, 命名为TaskA(TaskA堆栈状态: A),在Activity A中启动Activity C,启动Activity C的Intent的Flag设为FLAG_ACTIVITY_NEW_TASK,Android系统会为Activity C开僻一个新的Task, 命名为TaskB(TaskB堆栈状态: C), 在Activity C中启动Activity D(TaskB的状态: CD) 长按Home键, 选择TaskA, Activity A回到前台, 再次启动Activity C(从桌面或者ActivityA启动,也是一样的),这时TaskB回到前台, Activity D显示,供用户使用。
==>说明了在此种情况下设置FLAG_ACTIVITY_NEW_TASK后,会先查找是不是有Activity C存在的栈,根据亲和性(taskAffinity),如果有,刚直接把这个栈整体移动到前台,并保持栈中的状态不变,即栈中的顺序不变

FLAG_ACTIVITY_NO_ANIMATION

  如果在Intent中设置,并传递给Context.startActivity()的话,这个标志将阻止系统进入下一个Activity时应用 Acitivity迁移动画。这并不意味着动画将永不运行——如果另一个Activity在启动显示之前,没有指定这个标志,那么,动画将被应用。这个标志可以很好的用于执行一连串的操作,而动画被看作是更高一级的事件的驱动。

FLAG_ACTIVITY_NO_HISTORY

  如果设置,新的Activity将不再历史stack中保留。用户一离开它,这个Activity就关闭了。这也可以通过设置noHistory特性。

FLAG_ACTIVITY_NO_USER_ACTION

  如果设置,作为新启动的Activity进入前台时,这个标志将在Activity暂停之前阻止从最前方的Activity回调的onUserLeaveHint()。
  典型的,一个Activity可以依赖这个回调指明显式的用户动作引起的Activity移出后台。这个回调在Activity的生命周期中标记一个合适的点,并关闭一些Notification。
  如果一个Activity通过非用户驱动的事件,如来电或闹钟,启动的,这个标志也应该传递给Context.startActivity,保证暂停的Activity不认为用户已经知晓其Notification。

FLAG_ACTIVITY_PREVIOUS_IS_TOP

  If set and this intent is being used to launch a new activity from an existing one, the current activity will not be counted as the top activity for deciding whether the new intent should be delivered to the top instead of starting a new one. The previous activity will be used as the top, with the assumption being that the current activity will finish itself immediately.

FLAG_ACTIVITY_REORDER_TO_FRONT

  如果在Intent中设置,并传递给Context.startActivity(),这个标志将引发已经运行的Activity移动到历史stack的顶端
  例如,假设一个Task由四个Activity组成:A,B,C,D。如果D调用startActivity()来启动Activity B,那么,B会移动到历史stack的顶端,现在的次序变成A,C,D,B。如果FLAG_ACTIVITY_CLEAR_TOP标志也设置的话,那么这个标志将被忽略

FLAG_ACTIVITY_RESET_TASK_IF_NEEDED

  If set, and this activity is either being started in a new task or bringing to the top an existing task, then it will be launched as the front door of the task. This will result in the application of any affinities needed to have that task in the proper state (either moving activities to or from it), or simply resetting that task to its initial state if needed.

一般为系统使用,比如要把一个应用从后台移到前台,有两种方式:从多任务列表中恢复(不包含该flag);从启动器中点击icon恢复(包含该flag);需结合FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET | FLAG_ACTIVITY_NEW_DOCUMENT (API21)理解。

FLAG_ACTIVITY_SINGLE_TOP

  如果设置,当这个Activity位于历史stack的顶端运行时,不再启动一个新的
注意:如果是从BroadcastReceiver启动一个新的Activity,或者是从Service往一个Activity跳转时,不要忘记添加Intent的Flag为FLAG_ACTIVITY_NEW_TASK。

taskAffinity

  每个Activity都有taskAffinity属性,这个属性指出了它希望进入的Task。如果一个Activity没有显式的指明该 Activity的taskAffinity,那么它的这个属性就等于Application指明的taskAffinity,如果 Application也没有指明,那么该taskAffinity的值就等于包名。而Task也有自己的affinity属性,它的值等于它的根 Activity的taskAffinity的值。

  TaskAffinity属性主要和SingleTask启动模式或者allowTaskReparenting属性配对使用,在其他情况下没有意义。当TaskAffinity和singleTask启动模式配对使用的时候,他是具有该模式的Activity的目前任务栈的名字,待启动的Activity会运行在名字和TaskAffinity相同的任务栈中。allowTaskReparenting用于配置是否允许该activity可以更换从属task,通常情况二者连在一起使用,用于实现把一个应用程序的Activity移到另一个应用程序的Task中。allowTaskReparenting用来标记Activity能否从启动的Task移动到taskAffinity指定的Task,默认是继承至application中的allowTaskReparenting=false,如果为true,则表示可以更换;false表示不可以。

  如果加载某个Activity的intent,Flag被设置成FLAG_ACTIVITY_NEW_TASK时,它会首先检查是否存在与自己taskAffinity相同的Task,如果存在,那么它会直接宿主到该Task中,如果不存在则重新创建Task。

若是已经启动了四个Activity:A,B,C和D,在D Activity里,想再启动一个Actvity B,但不变成A,B,C,D,B,而是A,C,D,B,则可以像下面写代码:

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

常见问题:

将一个 Activity 设置成窗口的样式:

只需要给我们的 Activity 配置如下属性即可。
注意:当前Activity继承自Activity,而不是AppCompatActivity,否则会报主题的错误。

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

如何退出 Activity?如何安全退出已调用多个 Activity 的 Application?

方法1、通常情况用户退出一个 Activity 只需按返回键,我们写代码想退出 activity 直接调用 finish()方法就行。

方法2、application 记录打开的 Activity
每打开一个 Activity,就记录下来。在需要退出时,关闭每一个 Activity 即可。

private List<Activity> mActList = new LinkedList<>();// 在 application 全局的变量里面    public void addActivity(Activity activity) {        if (mActList.contains(activity)) {            mActList.remove(activity);        }        mActList.add(activity);    }    public void exit() {        try {            for (Activity activity : mActList) {                if (activity != null)                    activity.finish();            }        } catch (Exception e) {            e.printStackTrace();        } finally {            System.exit(0);        }    }

方法3、发送特定广播
在需要结束应用时,发送一个特定的广播,每个 Activity 收到广播后,关闭即可。

//给每个 activity 注册接受接受广播的意图registerReceiver(receiver, filter)//如果过接受到的是 关闭 activity 的广播   就调用 finish()方法 把当前的 activity finish()掉

或者eventBus

//发送方EventBus.getDefault().post(map);//接收方    @Override    public View onCreateView(LayoutInflater inflater, ViewGroup container,                             Bundle savedInstanceState) {        EventBus.getDefault().register(this);        ...    }    @Override    public void onDestroyView() {        EventBus.getDefault().unregister(this);        super.onDestroyView();    }    public void onEventMainThread(HashMap<String, String> map) {      finish();    }

方法4、递归退出
在打开新的 Activity 时使用 startActivityForResult,然后自己加标志,在 onActivityResult 中处理,递归关闭。

方法5、其实 也可以通过 intent 的 flag 来实现 intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)激活 一个新的 activity。此时如果该任务栈中已经有该 Activity,那么系统会把这个 Activity 上面的所有 Activity 干掉。其实相当于给 Activity 配置的启动模式为 SingleTop。

引用:
关于Activity的生命周期
onCreate & onStart & onResume & onStop & onPause & onDestroy & onRestart & onWindowFocusChanged
Activity的四种启动模式和onNewIntent()
关于代码实现activity的启动模式
Intent相关FLAG介绍和Activity启动模式
android深入解析Activity的launchMode启动模式,Intent Flag,taskAffinity
Activity的启动方式和flag详解
Android Intent.FLAG_NEW_TASK详解,包括其他的标记的一些解释

原创粉丝点击