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

adb shell dumpsys activity

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

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

1471964912640571.png

从图中可以看出,有两个 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 中写入启动模式,如下:

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

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

A(null)

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

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

在 manifest 中这样写:

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

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

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

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

用逻辑来表达,就像是这样: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″)AB

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

manifest 如下:

(1). A -> BTask 1 (affinity=”cn.six.adv”)Task 2 (affinity=”task2″)AB

(2) A -> B -> C

因为 C 的 affinity 是 “task2” ,而 Task 中已经有一个和它一样属性值的 B ,所以 C 会被放在 Task 2 中。Task 1 (affinity=”cn.six.adv”)Task 2 (affinity=”task2″)AC B

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

首先看一下实际结果Task 1 (affinity=”cn.six.adv”)Task 2 (affinity=”task2″)AB

好奇怪啊! C 去哪里啦?

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

4. SingleTask 小结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 -> BTask 1Task 2AB

(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 1Task 2c AB

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

如何去运用启动模式呢?

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

Service 是 Context 一种扩展, 它含有 startActivity(intent) 方法。但是当你调用service.startActivity(intent)时,你的程序必然会崩。报错如下: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 之中:// "this" is a service

Intent it = new Intent(this, ActivityB.class);

it.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

this.startActivity(it);

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Android中,我们可以使用隐式意图(Intent)来打开一个新的Activity。隐式意图是指没有明确指明目标组件的意图,而是通过指定一些匹配条件来启动匹配的组件。 下面是一个使用隐式方式打开一个新的Activity的示例代码: ```java Intent intent = new Intent(); intent.setAction("com.example.action.OPEN_NEW_ACTIVITY"); intent.addCategory("android.intent.category.DEFAULT"); startActivity(intent); ``` 上面的代码中,我们首先创建了一个Intent对象,然后通过调用setAction()方法来设置Action,这里设置的是"com.example.action.OPEN_NEW_ACTIVITY"。接着,我们调用addCategory()方法来添加Category,这里添加的是"android.intent.category.DEFAULT"。最后,我们调用startActivity()方法来启动Activity。 在这个示例中,我们没有明确指定要启动哪个Activity,而是通过设置Action和Category来启动匹配的Activity。具体来说,我们要求被启动的Activity必须满足以下条件: - Action为"com.example.action.OPEN_NEW_ACTIVITY"。 - Category包含"android.intent.category.DEFAULT"。 如果有多个Activity同时满足这些条件,系统会弹出一个选择对话框让用户选择要启动的Activity。 需要注意的是,如果要使用隐式方式启动Activity,需要在被启动的ActivityAndroidManifest.xml文件中设置正确的Intent过滤器。具体来说,需要在<activity>标签中添加一个<intent-filter>标签,并在其中设置Action和Category。例如: ```xml <activity android:name=".NewActivity"> <intent-filter> <action android:name="com.example.action.OPEN_NEW_ACTIVITY" /> <category android:name="android.intent.category.DEFAULT" /> </intent-filter> </activity> ``` 上面的代码中,我们在<activity>标签中添加了一个<intent-filter>标签,并在其中设置了Action和Category,这样就可以响应隐式意图了。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值