Activity的正确打开方式

Android Activity启动流程○ 从点击屏幕上的应用icon,到该应用展示第一个可视界面,这个过程中,Android系统究竟做了什么操作?又涉及到哪些进程? 1.根Activity启动过程 ①从Launcher到AMS 当点击屏幕上的应用icon时,Laucher发送启动应用的请求给AMS,因为Launcher是在Launcher进程,而AMS是在SystemServer进程。因此,实现这个请求,本质上是在实现一个跨进程通信的功能。在安卓领域实现跨进程通信的技术有多种,像是Broadcast、ContentProvinder等。在系. 阅读详情

Activity的正确打开方式

adb shell dumpsys activity

输入这个命令可以得到一个清晰的 Task 视图,比如你有多少个 Task ,哪些 activity 在其对应的 Task 等相关信息。

下图是一张运行这个命令的输出截图。

从图中可以看出,有两个 Task (#103, #102) 。

Task #103 : affinity = “cn.six.task2”, size = 3 (它里面有三个activity)

— Activity One
— Activity Three
— ActivityTwo

Task #102 : affinity = “cn.six.adv”, size = 1

— Activity One

拥有了这个神奇的命令—— “adb shell dumpsys activity” ,我们就可以更好地探索 Activity 的启动模式啦…

Default

到达此 activity 的 Intent ,系统会默认地在目标 Task 中创建一个新的实例并将默认的启动模式属性设置为 "default" 。

“Default” 是 activity 的默认启动模式,也就是说当你未给 activity 指定启动模式的时候,系统默认会给一个 “Default” 作为它的启动模式。

SingleTop

如果一个启动模式为 SingleTop 的 activity 实例在目标栈顶,intent 启动该 activity 时系统将通过 onNewIntent 的方法将 intent 传递给已有的那个实例而不会新创建一个的实例。

注意:并不是清除栈顶的 activity !!!(也就是说只要栈顶不是本 activity ,都会创建新的实例,是本 activity 则重用不新建)。

SingleTask

这个是最难理解的,下文中我会搭配几个例子来细细讲解这个复杂的启动模式。

1. A(Default) -> B(singleTask)

我们有两个 Activity ,A 和 B ,其中 B 是 SingleTask 模式,现在从 A 跳转到 B 。

首先在 Manifest 中写入启动模式,如下:

1
2
3
4
5

<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="cn.six.adv">
    <Activity android:name=".A"/>
    <Activity android:name=".B" android:launchMode="singleTask"/>
</manifest>

Android 官方文档中提到 “ intent 启动一个(SingleTask) 的 Activity ,系统会将这个 Activity 创建在一个新的 Task 根部”。 SO ,听起来会是这个样子?

Task 1 Task 2
A B

但实际上,当我们运行命令 “adb shell dumpsys activity” 时,发现 B 这货诡异地和 A 出现在一个 Task 中。

Task 1 Task 2
B  
A (null)

这个问题有一点小难表达,因为这里面 B 使用了 android:taskAffinity 属性。 后文中会有详解。

2. A(Default) -> B(singleTask) : B has a taskAffinity attribute

在 manifest 中这样写:

1
2
3
4
5

<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="cn.six.adv">
    <activity android:name=".A"/>
    <activity android:name=".B" android:launchMode="singleTask" android:taskAffinity="task2"/>
</manifest>

在这里, A 启动 B 的效果就不一样啦。如下:

Task 1 Task 2
A B

这个和上一个例子的唯一不同就是属性 “android:taskAffinity” 。 当你不声明 affinity 属性, 那么 activity 就会以包名作为其默认值。在这个例子中, 默认的 affinity 值就是 “cn.six.adv” 。

当 A 启动 B ,即使 B 的启动模式是 singleTask ,但也只有当 android:taskAffinity 属性和 A 不同时才会创建新的 task 。

看到这里,第一个例子是不是就顿时豁然开朗? 为什么 A 和 B 在同一个 Task 中呢?因为它们的 taskAffinity 属性值是一样滴。

用逻辑来表达,就像是这样:

1
2
3
4
5
6
7
8
9

A --> B

  if( taskAffinity 属性相同) { 
    A 和 B 在同一个 Task 中
  }
  else { 
    B 在新的 Task 中,并且此 Task 的 affinity 属性值就是 B 
  }

那么这个例子中, A 跳转 B, B 的启动模式是 “singleTask” , 并且 B 的 taskAffinity 不是 “cn.six.adv” 。 所以 B 会在一个新建的 Task 中。

Task 1 (affinity=”cn.six.adv”) Task 2 (affinity=”task2″)
A B

3. A(default) -> B(singleTask) -> C(singleTask) -> B(singleTask)

manifest 如下:

1
2
3
4
5
6

<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="cn.six.adv">
    <activity android:name=".A"/>
    <activity android:name=".B" android:launchMode="singleTask" android:taskAffinity="task2"/>
    <activity android:name=".C" android:launchMode="singleTask" android:taskAffinity="task2"/>
</manifest>

(1). A -> B

Task 1 (affinity=”cn.six.adv”) Task 2 (affinity=”task2″)
A B

(2) A -> B -> C

因为 C 的 affinity 是 “task2” ,而 Task 中已经有一个和它一样属性值的 B ,所以 C 会被放在 Task 2 中。

Task 1 (affinity=”cn.six.adv”) Task 2 (affinity=”task2″)
A C B

(3) A -> B -> C -> B

首先看一下实际结果

Task 1 (affinity=”cn.six.adv”) Task 2 (affinity=”task2″)
A B

好奇怪啊! C 去哪里啦?

事情呢,是这个样子滴。 C->B , B 的启动模式是 singleTask 而且它的 affinity 属性值是 “task2”, 当系统发现有一个 affinity 属性值为 task2 的 Task 2 所以就把 B 放进去了。但是, 其中已经有一个 B 的实例在 Task 2 之中。 所以系统会将已有的 B 的实例赋予一个 CLEAR_TOP(清除顶部)标志。所以 C 是这么没的。

4. SingleTask 小结

1
2
3
4
5
6
7
8
9
10
11

if( 发现一个 Task 的 affinity == Activity 的 affinity ){
    if(此 Activity 的实例已经在这个 Task 中){
        这个 Activity 启动并且清除顶部的 Acitivity ,通过标识 CLEAR_TOP 
    } else {
        在这个 Task 中新建这个 Activity 实例
    }
} else { // Task 的 affinity 属性值与 Activity 不一样
    新建一个 affinity 属性值与之相等的 Task
    新建一个 Activity 的实例并且将其放入这个 Task 之中
}

SingleInstance

SingleInstance 要比 SingleTask 好理解很多。

如果一个 Activity 的启动模式为 SingleInstance, 那么这个 Activity 必定会在一个新的 Task 之中, 并且这个 Task 之中有且只能有一个 Activity 。

再来一波栗子。

1. A(default) –> B(singleInstance) –> C(default)

(1). A -> B

Task 1 Task 2
A B

(2). A -> B -> C

拥有 “singleInstance” 启动模式的 activity 不予许其他任何 Activity 在它的 Task 之中。所以它是这个 Task 之中的独苗啊。当它跳转另外一个 activity 时, 那个 Activity 将会被分配到另外一个 Task 之中——就像是 intent 被赋予了 FLAG_ACTIVITY_NEW_TASK 标志一样。

由于 B 需要一个只能容纳它的 Task , 所以 C 会被加上一个 FLAG_ACTIVITY_NEW_TASK 标识。所以 C(default) 变成了 C(singleTask) 。

然后结果变成了这样:

Task 1 Task 2
c A B

注:如果跳转的流程是 “A(default) –> B(singleTask) –> C(default)”, 那么结果会是这样:

Task 1 Task 2
A C B

如何去运用启动模式呢?

假如, 你需要在 service 在后台中做一些耗时操作,当它完成时, 你需要从此 service 中跳转进入一个 Activity 中,你会怎样做?

Service 是 Context 一种扩展, 它含有 startActivity(intent) 方法。但是当你调用service.startActivity(intent)时,你的程序必然会崩。报错如下:

1
2
3
4
5

AndroidRuntimeException :   
            "Calling startActivity() from outside of an Activity context 
            requires the FLAG_ACTIVITY_NEW_TASK flag. 
            Is this really what you want?"

这就是上文中提到的。当一个 Activity A 跳转进入另一个 Activity B (它们的启动模式都为默认的 default ), 所以这个 B 会和 A 在一个 Task 之中。但是当你想让 service 跳转到 Activity B, 由于 service 并不是一个 Activity , 所以它没有相关的 task 信息。所以 Service 不会出现在 Activity 的任务栈之中。这种情况下,Activity B 就不知道自己的 Task 在哪里了。

为了解决上述问题,我们可以告诉 Activity B 它应该在一个新的 Task 之中:

1
2
3
4
5

// "this" is a service
Intent it = new Intent(this, ActivityB.class); 
it.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
this.startActivity(it);

瞅见没?这才是 Activity 的启动模式的正确打开方式。

Android 开发中 Activity正确打开方式 adb shell dumpsys activity 输入这个命令可以得到一个清晰的 Task 视图,比如你有多少个 Task ,哪些 activity 在其对应的 Task 等相关信息。 下图是一张运行这个命令的输出截图。 从图中可以看出,有两个 Task (#103, #102... 阅读详情

相关推荐

Activity的启动和结束

看一个示例,Activity3 设置为singleInstance,Activity1 和 Activity2 默认(standard),下图程序流程中,黄色的代表 Background 的Task,蓝色的代表 Foreground 的Task。对于不允许重复返回的情况,可以设置启动标志FLAG_ACTIVITY_CLEAR_TOP,即使活动栈里面存在待跳转的活动实例,也会重新创建该活动的实例,并清除原实例上方的所有实例,保证栈中最多只有该活动的唯一实例,从而避免了无谓的重复返回。

qq_45412648的博客 1万+

activity 典型生命周期

抄录部分 安卓生命周期如下: onCreate : 该方法是在Activity被创建时回调,它是生命周期第一个调用的方法,我们在创建Activity时一般都需要重写该方法,然后在该方法中做一些初始化的操作,如通过setContentView设置界面布局的资源,初始化所需要的组件信息等。 onStart : 此方法被回调时表示Activity正在启动,此时Activity已处于可见状态,只是还没有在...

定格空间 358

Android Activity启动过程详解

ctivity启动的流程分为两部分:一是在activity中通过startActivity(Intent intent)方法启动一个Activity;二是我们在桌面通过点击应用图标启动一个App然后显示Activity;第二种方式相较于第一种方式更加全面和复杂,所以本文会以第二种流程来分析。应用的启动流程大致分为下面五个阶段:1,应用启动进程 Launcher 调用 ATMS 系统进程的过程2,ATMS 向 AMS 发送创建应用进程的过程。

allen_xu_2012_new的博客 1万+

android 打开方式有哪些,Activity正确打开方式

原标题:Activity正确打开方式本文来自稀土掘金翻译计划的投稿,Liz 同学翻译,是这几天掘金上的热文。主题比较基础但是写得不错,越是基础的东西有时候越是需要清晰掌握,相信会对一些同学有帮助,推荐给还没看过的同学阅读。...

weixin_33218378的博客 142

Activity正确打开方式

adb shell dumpsys activity 输入这个命令可以得到一个清晰的Task视图,比如你又多少个Task,那些Activity在其对应的Task的信息。 1.Default 为了达到此Activity的intent系统会默认的在Task中创建一个新的实例,启动模式默认为Defauat(Defauat为Acitvity默认启动方式) 2.SingleTop 如果

dahidljal的博客 316

Activity--onSaveInstanceState正确打开方式

背景之所以会写这篇文章,是因为之前偶然看见csdn的博客专家写到这个问题,给出的结论实在让人大跌眼镜。于是看了下源码,索性做个记录。在Android 7.0以前,谷歌一直约束着让它以单窗口的姿态与广大用户见面(当然,除了个别不听话的厂商,早已实现了多窗口)。从开发者的角度来看,Activity(Fragment)通常是我们与用户交互的载体,也就是象征意义的“窗口”。通常我们的应用一般会有多个Acti

luochoudan的专栏 1119

Android开发笔记】返回上层Activity正确打开方式

技术支持http://stackoverflow.com/questions/12276027/how-can-i-return-to-a-parent-activity-correctly 首先,在网上看到有人这么写: 1 @Override 2 public boolean onOptionsItemSelected(MenuItem item) { 3 ...

weixin_33711641的博客 232

android 添加到打开方式,【Android开发笔记】返回到上一个Activity正确打开方式...

首先,在网上看到有人这么写:1 @Override2 public booleanonOptionsItemSelected(MenuItem item) {3 switch(item.getItemId()) {4 caseandroid.R.id.home:5 this.getActivity().finish()...

weixin_39627408的博客 135

activity 防止多次打开_冬季吃火锅的正确打开方式,这么吃才健康!

吃货特刊冬季吃火锅的正确打开方式,这么吃才健康!2020年12月14日天气:晴心情:想吃火锅没有什么坏心情是一顿美味的火锅解决不了的,如果有,那就两顿。冬季空气寒冷干燥,在这个季节与亲朋好友坐在一起惬意地吃着热腾腾的火锅,实乃冬季一大享受,但吃火锅是有讲究的,我们应该如何健康的吃火锅呢?冬季吃火锅的注意事项 火锅安全方面 炭火锅我们用炭作为燃料时要注意生炭安全,在火锅下面放一个盘子,再放一些清水,...

weixin_29325007的博客 106

activity 防止多次打开_孕妇补钙关键要适量,这才是孕妇补钙的正确打开方式!...

欢迎在右上角点击关注:「海螺宝宝」,不定时发送福利,让您干货满满哦~随着经济、教育水平的提升,大家越来越注重科学的补充营养。而“补钙”几乎是全民都行动起来,小孩补钙能长高,老人补钙可以防止骨质疏松,而孕妇补钙促进胎儿的健康发育。你知道孕妇补钙会促进胎儿的发育,但你知道到底具体能促进胎儿的哪些发育吗?第一、孕妇补钙能促进胎儿的骨骼发展。胎儿的骨骼和牙齿的钙化在两个月时已经开始,八个月后突然开始加速,...

weixin_39664995的博客 219

activity 防止多次打开_万科湖语森林别墅,地下室正确打开方式

万科湖语森林别墅位于上海安亭南安德路无论是地理位置还是周边设施来看该小区均占据一定优势拥有魔都适宜的人居环境走进别墅区,一池稀世蓝宝石色的天然湖散发着高雅、安静,沉稳气息借助自然优势户主们能拥有一处生机勃勃鸟语花香,沁人心脾的四季景象的生活场所作为联排叠加别墅中的精品,万科湖语森林小区一直深受户主好评,更令人惊喜的是下叠户主获得的意向不到的地下室空间提升,40~140㎡的超大空间着实给户...

weixin_36310396的博客 387

Android组件安全第一课:你的Activity该不该‘开门迎客’?聊聊android:exported的正确打开方式

本文深入解析Android组件安全中的`android:exported`属性,探讨如何正确配置Activity的访问控制策略。通过分析底层权限检查机制、默认值差异及多层级防御方案,帮助开发者避免常见安全陷阱,确保组件既不被恶意调用,又能满足必要的功能需求。重点介绍了权限声明、动态校验及典型场景下的最佳实践。

weixin_33725239的博客 264
上一篇: android实现之高清音频录制编码
下一篇: 如何有效的清除Android中无用的资源(静态代码分析)
战码天下
博客等级 码龄16年 11粉丝 5原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值