Activity的启动模式

待学的

  • 任务栈

Activity的 lauchMode

在android系统默认状态下,当我们启动activity的时候,系统会创建多个实例,并把它们放到一个任务栈中,当我们回退的时候,这些Activity 会一一回退。 任务栈是一个“先进后出”的站结构,当栈中内容为空的时候,系统会回收这个任务栈。 在创建 activity 的时候,有四种启动方式,下面以一一列举:

  1. standard 标准的启动模式,也系统默认启动模式。 每次启动都会重建一个新的实例。它的 onCreate、 onStart、onResume 都会被调用。
    一个任务栈可以有多个实例,每个实例可以属于不同的任务栈。 在这种模式下,谁启动了这个activity,那么这个activity就运行在谁的任务栈中。
    当使用 ApplicationContext 去启动 standard 模式的activity时候,会报错;
    这是因为非 activity 类型的 context 并没有所谓的任务栈,所以会出现问题。解决方法就是为待启动的activity指定 FLAG_ACTIVITY_NEW_TASK 标记位,这样启动的时候就会新建一个任务栈,这时候,实际以 singleTask 模式启动的。

  2. singleTop 栈顶复用模式。这种模式下,如果该 Activity 已经有实例位于栈顶, 那么该 activity 的实例不会被重新重建,同时它的 onNewIntent 方法会被回调,但是 onCreate、onStart 等不会被调用。

  3. singleTask 栈内复用模式。这是一种单例模式,在这种模式下,只要栈存在于需要的任务栈中,多次调用都不会重新创建实例, 系统也会回调 OnNewIntent。
    具体说:当一个具有 singleTask 模式的activity A请求启动后, 系统首先会寻找是否存在 A 想要的任务栈, 如果不存在,就新建一个任务栈,然后创建 A的实例后放入栈中。 如果A所需的任务栈存在,这时要看A是否在栈中有实例存在, 如果有实例存在,系统会把A调到栈顶并调用它的 onNewIntent, 如果实例不存在,就创建A的实例,并压入栈中。

singleTask 默认具有 clearTop 的效果, 会导致已存在的实例之上的activity全部出栈。

  1. singleInstance 单实例模式,这是一种加强的 singleTask 模式,它除了具有 singleTask 模式的所有特性以外, 还加强了一点,那就是具有此种模式的 activity 只能单独地位于一个栈中。比如 Activity A是singleInstance 模式, 当A启动以后,系统会为它创建一个新的任务栈,然后 A 独自存在在这个新的任务栈中,由于栈内复用的特点, 后续均不会创建新的实例,除非这个独特的任务栈被系统销毁了。

几个问题

问题1: 文中提到的某个 activity所需的任务栈, 什么是 activity 所需要的任务栈呢?

这要从一个参数说起: TaskAffinity 翻译为任务相关性。这个参数标识了一个 activity 所需要的任务栈的名字,默认情况下,所有 activity 所需的任务栈的名字为应用的包名。 当然我们可以为每个 activity 单独指定 taskaffinity 属性,这个属性要和包名不同, 否则相当于没指定。
TaskAffinity 属性主要和 singleTask 或者 allowTaskReparenting 属性配对使用,其他情况下没意义。

当TaskAffinity和singleTask启动模式配对使用的时候, 他是具有该模式的 Activity 的目前任务栈的名字,待启动的 activity 会运行在名字和 taskAffinity 名字相同的任务栈中。

问题2 什么情况下 TaskAffinity 会生效?

只有Activity设置了 lauchMode = "singleTask" 或者 allowTaskReparenting 才起作用

Activity 的 Flags

Activity 的标记位有很多,列举一些常用的标记位。标记位有多种作用。可以设定Activity的启动模式,也可以影响 activity 的运行状态。

影响启动模式的:

  • FLAG_ACTIVITY_NEW_TASK 等同于xml设置 "singleTask"启动模式
  • FLAG_ACTIVITY_SINGLE_TOP 等同于 xml 中设置 "singleTop"启动模式

影响运行状态的:

  • FLAG_ACTIVITY_CLEAR_TOP 如果启动模式为 "singleTask",且该activity已存在,则清除栈中该activity之上的,只调用 onNewIntent() ,不重新启动。
    如果启动模式为 “standard”,那么它连同它之上的都要出栈,系统会创建新的 activity并放入栈顶。
  • FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS 具有这个标记的不会出现在历史 activity 列表中,相当于在 xml 中设置属性 android:excludeFromRecents="true"

IntentFilter 的匹配规则

启动 Activity 有两种方式,显式启动和隐式启动。
显式启动要指定被启动的组件信息,比较简单具体不谈。
隐式启动则需要 intent 能够匹配目标组件的 IntentFilter 中所设置的过滤信息。

IntentFilter 中的过滤信息有 action、category、data 三个类别,给了匹配过滤列表需要同时匹配列表中的 action, category, data信息。一个activity可以有多个 IntentFilter, 一个intent只要能匹配其中一组 intentFilter 就可以启动对应的 activity。

  • action 的匹配规则

action 是一个字符串,一个intent一般只携带一个action。如果携带多个action,则都要在 IntentFilter中包含才能正常启动,但如果 Intent 中没有指定 action 则匹配失败。 匹配时严格区分大小写。 intent.setAction("..........")

  • category 的匹配规则

category 是一个字符串。 如果 intent 中携带 category,不管携带几个,都要在 IntentFilter 中找到相匹配的才能启动,若不携带, 系统会默认设置 "android.intent.category.DEFAULT"这个 category,所以在 IntentFilter 中至少要设置 <category android:name="android.intent.category.DEFAULT"/> 这一个配置项。否则启动失败。

  • data 的匹配规则
    data 的匹配规则和 action 类似, 但是 data 要复杂的多,先了解一下data 的结构 :
<data android:scheme="String"
          android:host="String"
          android:port="String"
          android:path="String"
          android:pathPattern="String"
          android:pathPrefix="String"
          android:mimeType="String"/>

data由两部分组成: mimeType 和 URL.
mimeType 指媒体类型,如 text/plain,image/jpeg, audio/mpeg4-generic 和 video/* 等,可以表示 文本,图像,音频,视频等不同的媒体格式。
URL 包含的数据略多, 下面是 URL 的结构:

<scheme>://<host>:<port>/[<path>|<pathPrefix>|<pathPattern>]

例子:
content://com.example.project:200/floder/subfloder/etc
http://www.baidu.com:80/search/info

每个数据的含义:
scheme: URL的模式,如 http, file, content 等,如果URL中没有指定 scheme,那么整个 URL 的其他参数无效,也就意味着URL无效。

Host: URL的主机名,比如 www.baidu.com, 如果 host 未指定,则其他参数无效,URL也无效。

Port : 端口号, 只有指定了 scheme 和 host 时候, port 才有意义。

Path, PathPrefix, PathPattern: 这三个参数表述路径信息,其中 path 表示完整的路径信息;pathPattern

示例1:

<intent-filter>
    <data android:mimeType=" image/* " />
    ......
</intent-filter>

这种规则制定了媒体类型为照片,那么intent中的mimeType为“ image/* ”才能匹配,这种情况下没有指定URL, 但是有默认值, 默认值是 content 和 file, 也就是说,虽然没有指定 URL,但是 intent 中的URL部分的 scheme 必须为 content 或者 file 才能匹配。

另外,想要为 Intent 指定完整的data,必须要使用 inent.setDataAndType, 不能先使用 setData 后使用 setType ,这样会清除对方的置。

实例2:

<intent-filter>
    <data android scheme="http"  ....    android:mimeType=" video/mpeg " />
    <data android scheme="http"  ....    android:mimeType=" audio/mpeg " />
    ......
</intent-filter>

这种规则指定了两组 data, 为了匹配实例2的规则,正确的 intent 应该如下:

intent.setDataAndType(Url.parse("http://abc"), "video/mpeg");
或者是
intent.setDataAndType(Url.parse("http://abc"), "audio/mpeg");

最后, 如果,匹配不到合适的 activity 怎么办?只能奔溃么?

当我们隐式启动一个 Activity 的时候,可以做一下判断,看是否能够匹配我们的 Intent 。方法有两种, 都在 Context 中:

public abstract List<ResolveInfo> getPackageManager().queryIntentActivities(Intent intent,int flag)
或者
public abstract ResolveInfo getPackageManager().resolveActivity(Intent intent,int flag);

上述两个方法,第一个参数没什么好说的, 第二个参数,我们要使用 PackageManager.MATCH_DEFAULT_ONLY 这个标记, 这个标记的含义是仅仅匹配那些在 intent-filter 中声明了 <category android:name="android.intent.category.DEFAULT"> 这个 Catrgory 的 activity, 是要返回不为null, 那么就有匹配到的activity, 就一定能隐式启动成功。因为不含有 DEFAULT 这个category 的activity 是无法接受隐式intent的。

在匹配规则中, 有一类 action 和 category 比较重要,那就是:

<action android:name="anroid.intent.action.MAIN"/>
<categoty android:name="android.intent.category.LAUCHER"/>

这两者公共来表明一个入口 activity,并且会出现在Home Launcher上。少了任何一个都不行。如果在 Intent-Filter 中还有data选项, 则不匹配限制条件,不能出现在 Home Laucher上。 如下面这种 intent-filter:

<activity android:name=".MainActivity">
    <intent-filter>
        <action android:name="android.intent.action.MAIN"/>

        <category android:name="android.intent.category.LAUNCHER"/>
        <category android:name="android.intent.category.BROWSABLE"/>
        <category android:name="android.intent.category.DEFAULT"/>
       
        <data android:scheme="urlscheme"
            android:host="auth_activity">
    </intent-filter>
</activity>

针对 service 和 BroadcastReceiver ,PacketManager 同样提供了类似的方法去获取成功匹配的组件信息。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,948评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,371评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,490评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,521评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,627评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,842评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,997评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,741评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,203评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,534评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,673评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,339评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,955评论 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,770评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,000评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,394评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,562评论 2 349

推荐阅读更多精彩内容