Activity 任务栈和它的启动模式

一、Activity 的 LaunchMode

1.1、standard:标准模式,这也是系统的默认模式

  • 每次启动一个 Activity 都会重新创建一个新的实例,不管这个实例是否已经存在。
  • standard 模式的 Activity 默认会进入启动它的 Activity 所属的任务栈中。

1.2、singleTop:栈顶复用模式

  • 如果新 Activity 位于任务栈的栈顶,那么此 Activity 不会被重新创建,不再调用 onCreate、onStart,会回调 onNewIntent(Intent intent) 方法。

1.3、singleTask:栈内复用模式

  • 只要 Activity 在一个栈中存在,那么多次启动此 Activity 都不会重新创建实例,不再调用 onCreate、onStart,会回调 onNewIntent(Intent intent) 方法。
  • 如果栈内不存在,需要重新创建时,系统会寻找是否存在新 Activity 需要的任务栈,如果不存在,就重新创建一个任务栈,然后创建新 Activity 的实例后放到栈中。
  • 默认具有 clearTop 的效果,所有在此 Activity 上面的 Activity 全部出栈。

1.4、singleInstance:单实例模式

  • 这是一种加强的 singleTask 模式,具有 singleTask 模式的所有特性。
  • 这种模式的 Activity 只能单独存在于一个任务栈中。
  • 后续的请求均不会创建新的 Activity ,除非这个独特的任务栈被销毁了。

1.5、Activity 的任务栈

  • 默认情况下,所有 Activity 所需的任务栈的名字都为应用的包名。

  • 单独指定任务栈,需要设置 Activity 的属性 android:taskAffinity="",不能和包名相同,否则相当于没有指定。taskAffinity 属性主要和 singleTask 启动模式或者 allowTaskReparenting 属性配对使用,否则没有意义。
    1. taskAffinity 和 singleTask 启动模式配对的时候
    指定了具有 singleTask 启动模式的 Activity 的任务栈的名字,待启动的 Activity 会运行在 taskAffinity 指定的任务栈中。

    2. taskAffinity 和 allowTaskReparenting 配对的时候
    当一个应用 A 启动了应用 B 的某个 Activity 后,如果这个 Activity 的 allowTaskReparenting 属性为 true,那么当在桌面再次启动应用 B 后,此 Activity 会直接从应用 A 的任务栈转移到应用 B 的任务栈中。

  • 任务栈分为前台任务栈和后台任务栈,后台任务栈中的 Activity 处于暂停状态,用户可以通过切换将后台任务栈再次调到前台。

  • 假设目前有 2 个任务栈,前台任务栈为 AB,后台任务栈为 CD,那么启动 D 时和启动 C 时的情况如下。

在这里插入图片描述

在这里插入图片描述

1.6、给 Activity 指定启动模式

  • 通过 AndroidMenifest
        <activity
            android:name=".SecondActivity"
            android:configChanges="screenLayout"
            android:label="@string/app_name"
            android:launchMode="singleTask" />
  • 通过 Intent 标志位
        Intent intent = new Intent();
        intent.setClass(MainActivity.this, SecondActivity.class);
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        startActivity(intent);
  • 两者区别
  1. 优先级上,第二种高于第一种,当两种同时存在,以第二种为准。
  2. 限定范围有所不同,比如,第一种方式无法直接为 Activity 设定 FLAG_ACTIVITY_CLEAR_TOP 标识,而第二种方式无法为 Activity 指定 singleInstance 模式。

1.7、小栗子

  • 将 SecondActivity 和 ThirdActivity 都设成 singleTask 并指定 taskAffinity 属性为 “com.example.task1",注意这个 taskAffinity 属性的值为字符串,且中间必须包含有包名分隔符 “.”.
  • 在 MainActivity 中启动 SecondActivity,在 SecondActivity 中启动 ThirdActivity,在 ThirdActivity 中启动 MainActivity,最后再在 MainActivity 中启动 SecondActivity,最后按两次 back 键,会发现回到了桌面。
  • MainActivity 的启动模式为默认模式 standard。
    在这里插入图片描述

二、Activity 的 Flags

  • 这里只说几个常用标记位
  1. Intent.FLAG_ACTIVITY_NEW_TASK:为 Activity 指定 singleTask 启动模式。
  2. Intent.FLAG_ACTIVITY_SINGLE_TOP:为 Activity 指定 singleTop 启动模式。
  3. Intent.FLAG_ACTIVITY_CLEAR_TOP:当启动具有此标记位的 Activity时,在同一任务栈中的所有位于它之上的 Activity 都要出栈。
  4. Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS:具有此标记的 Activity 不会出现在历史 Activity 的列表中,相当于 XML 中 Activity 的 android:excludeFromRecents=“true” 属性。

三、IntentFilter 的匹配规则

3.1、显式调用

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

3.2、隐式调用
3.2.1、intent-filter

  • 一个 Activity 中可以有多组 intent-filter,一个 Intent 只要能匹配任意一组 intent-filter 即可成功启动对应的 Activity。Intent 必须同时匹配某一组 intent-filter 中的 action、category、data 才算完全匹配,只有完全匹配才能启动 Activity。
  • 一个 intent-filter 中的 action、category、data 都可以有多个。

3.2.2、action 匹配规则

  • Intent 中必须指定 action,并且要和 intent-filter 中的任意一个 action 相同(区分大小写),才能成功匹配。

3.2.3、category 匹配规则

  • 如果 Intent 中有 category,那么必须匹配 intent-filter 中的 category 。
  • Intent 不设置 category 也可以匹配,原因是系统在调用 startActivity 或者 startActivityForResult 时默认给 Intent 加上了 android.intent.category.DEFAULT,所以在隐式调用时 intent-filter 中必须加 <category android:name=“android.intent.category.DEFAULT” />。

3.2.4、data 匹配规则(关于 data 还存在疑问,仅供参考)

  • 如果 intent-filter 中定义了 data,那么 Intent 中必须指定 data,并且要和 Intent-filter 中的 data 相对应,才能成功匹配。
  • data 由两部分组成,mimeType 和 URL。
  • mimeType 指媒体类型,比如 image/jpeg、audio/mpeg4-generic 和 video/* 等,可以表示图片、文本、视频等不同的媒体格式。
  • 而 URI 中包含的数据就比较多了,下面是 URI 的结构。
<scheme>://<host>:<post>/[<path>|<|pathPrefix>|<pathPattern>]

// 比如
content://com.example.project:200/folder/subfolder/etc
http://www.baidu.com:80/search/info
  1. scheme:URI 中的模式,比如 http、file、content 等,如果 URI 中没有指定 scheme,那么整个 URI 的其他参数无效,这也意味着 URI 是无效的。
  2. host:URI 的主机名,比如 www.baidu.com,如果 host 未指定,那么整个 URI 的其他参数无效,这也意味着 URI 是无效的。
  3. port:URI 中的端口号,比如 80,仅当 URI 中指定了 scheme 和 host 参数的时候 port 参数才是有意义的。
  4. path、pathPrefix 和 pathPattern:这三个参数表述路径信息。
    path 表示完整的路径信息。
    pathPrefix 表示路径的前缀信息。
    pathPattern 也表示完整的路径信息,但是它里面可以包含通配符 “*”,“*” 表示 0 个或多个任意字符,需要注意的是,由于正则表达式的规范,如果想要表示真实的字符串,那么 “*” 要写成 “\\*”,"\"要写成 “\\\\”。

3.2.5、系统内部 Activity

这里没有做版本适配,如动态权限申请

  1. 拨打电话,
intent.setAction("android.intent.action.CALL");
intent.setData(Uri.parse("tel://13600000000"));
  1. 打开浏览器
intent.setAction("android.intent.action.VIEW");
intent.setData(Uri.parse("https://www.baidu.com/"));
  1. 播放音频
intent.setAction("android.intent.action.VIEW");
intent.setDataAndType(Uri.parse("file:///mnt/sdcard/Adele - Rolling in the Deep.mp3"), "audio/*");
  1. 播放视频
intent.setAction("android.intent.action.VIEW");
intent.setDataAndType(Uri.parse("file:///mnt/sdcard/1.mp4"), "video/*");
  1. 显示图片
intent.setAction("android.intent.action.VIEW");
intent.setDataAndType(Uri.parse("file:///mnt/sdcard/9.jpg"), "image/*");
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值