Activity 的启动模式|Flags|IntentFilter

以下是 Android 开发中 ​Activity 启动模式Flags ​ 及 ​IntentFilter​ 的核心知识点总结,结合官方文档及最佳实践整理:


⚙️ 一、Activity 的四种启动模式(Launch Mode)

  1. ​**standard(标准模式)​**​

    • 特点:每次启动均创建新实例,可存在多个相同 Activity。
    • 任务栈行为:新实例压入启动它的 Activity 所在栈。
    • 注意 :非 Activity 上下文(如 Service)启动时需添加 FLAG_ACTIVITY_NEW_TASK 避免报错。
    • 适用场景:普通页面(如新闻详情页)。
  2. ​**singleTop(栈顶复用模式)​**​

    • 特点 :若目标 Activity 位于栈顶,则复用实例并回调 onNewIntent();否则创建新实例。
    • 任务栈行为:避免栈顶重复创建。
    • 适用场景:通知跳转页、搜索结果页(避免重复打开同一页面)。
  3. ​**singleTask(栈内复用模式)​**​

    • 特点 :全局唯一实例,复用时会清空其上方所有 Activity 并回调 onNewIntent()
    • 任务栈行为 :默认在启动它的栈中,可通过 taskAffinity 指定新栈(需配合 FLAG_ACTIVITY_NEW_TASK)。
    • 适用场景:应用主界面(如微信首页),确保返回时直接回到根页面。
  4. ​**singleInstance(单实例模式)​**​

    • 特点:独占一个任务栈,不允许其他 Activity 共存。
    • 任务栈行为:跨应用共享实例(如闹钟提醒界面)。
    • 注意:过度使用可能导致内存开销增加。
模式 实例数量 清空栈上 Activity 独立任务栈
standard 多个
singleTop 栈顶唯一
singleTask 全局唯一 可选
singleInstance 全局唯一

🚩 二、常用 Activity Flags

通过 Intent.addFlags() 动态设置(优先级高于 Manifest 配置):

  • **FLAG_ACTIVITY_NEW_TASK**
    等同于 singleTask,在新栈中启动 Activity(常用于非 Activity 上下文)。
  • **FLAG_ACTIVITY_SINGLE_TOP**
    等同于 singleTop,栈顶复用。
  • **FLAG_ACTIVITY_CLEAR_TOP**
    清空目标 Activity 上方的所有 Activity。若目标非 singleTask 模式,会销毁自身并重建新实例。
  • **FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS**
    不保留在最近任务列表(同 android:excludeFromRecents="true")。
  • **FLAG_ACTIVITY_NO_HISTORY**
    Activity 退出后自动销毁(如登录跳转页)。

🔍 三、IntentFilter 匹配规则

隐式启动 Activity 需匹配目标组件的 IntentFilter,规则如下:

  1. Action 匹配

    • Intent 需包含至少一个 Filter 中声明的 Action(字符串完全一致,区分大小写)。
    • 示例:<action android:name="android.intent.action.SEND"/>
  2. Category 匹配

    • Intent 中的每个 Category 必须存在于 Filter 中。
    • 未声明 Category 时,系统默认添加 android.intent.category.DEFAULT,因此 Filter 必须包含该 Category。
  3. Data 匹配

    • 包括 MIME 类型 (如 image/*)和 URI(Scheme、Host、Port、Path)。
    • URI 结构:<scheme>://<host>:<port>/<path>(如 http://example.com:80/path)。
    • 注意 :使用 setDataAndType() 同时设置 URI 和 MIME 类型(避免 setData()setType() 互相覆盖)。
  4. 多 Filter 处理

    Activity 可声明多个 <intent-filter>,匹配任意一组即可启动。


IntentFilter 的匹配规则由 actioncategorydata 三部分构成,不同组合方式会影响隐式启动 Activity 的匹配逻辑。以下针对 ​四种常见配置情况​ 举例说明:


🔧 情况一:仅声明 action(无 categorydata

规则说明

  • **action 必须存在且匹配**:Intent 需包含与过滤规则中完全一致的 action(区分大小写)。
  • **必须添加默认 category**:即使未声明,系统会自动添加 android.intent.category.DEFAULT,否则无法接收隐式 Intent。

示例代码

xml 复制代码
<!-- AndroidManifest.xml -->
<activity android:name=".TextActivity">
    <intent-filter>
        <action android:name="com.example.ACTION_TEXT" />
        <category android:name="android.intent.category.DEFAULT" /> <!-- 必须显式添加 -->
    </intent-filter>
</activity>
ini 复制代码
// 匹配的 Intent
Intent intent = new Intent("com.example.ACTION_TEXT");
startActivity(intent);

⚠️ 匹配要点

  • 未声明 DEFAULT category 会导致匹配失败(常见报错:ActivityNotFoundException)。

🧩 情况二:同时声明 actioncategory(无 data

规则说明

  • **category 需完全覆盖**:Intent 中所有 category 必须能在过滤规则中找到匹配项。
  • **DEFAULT category 不可省略**:过滤规则中必须包含 android.intent.category.DEFAULT

示例代码

ini 复制代码
<activity android:name=".ShareActivity">
    <intent-filter>
        <action android:name="android.intent.action.SEND" />
        <category android:name="android.intent.category.DEFAULT" />
        <category android:name="com.example.CATEGORY_SHARE" />
    </intent-filter>
</activity>
scss 复制代码
// 匹配的 Intent
Intent intent = new Intent(Intent.ACTION_SEND);
intent.addCategory("com.example.CATEGORY_SHARE");
startActivity(intent);

⚠️ 匹配要点

  • Intent 若漏掉 com.example.CATEGORY_SHARE 则匹配失败;若额外添加未声明的 category 也会失败。

🌐 情况三:同时声明 actiondata(无显式 category

规则说明

  • **data 需严格匹配**:包括 URI 的 schemehostportpath 及 MIME 类型。
  • URI 默认值限制 :未显式声明 URI 时,默认 Scheme 为 contentfile

示例代码

ini 复制代码
<activity android:name=".ImageActivity">
    <intent-filter>
        <action android:name="android.intent.action.VIEW" />
        <category android:name="android.intent.category.DEFAULT" />
        <data android:scheme="https" android:host="example.com" android:mimeType="image/*" />
    </intent-filter>
</activity>
scss 复制代码
// 匹配的 Intent
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(Uri.parse("https://example.com/photo.jpg"), "image/jpeg");
startActivity(intent);

⚠️ 匹配要点

  • **避免使用 setData() + setType()**:二者互斥,应用 setDataAndType()
  • 若 URI 为 http://example.com 或 MIME 为 text/plain 均不匹配。

⚙️ 情况四:同时声明 actioncategorydata

规则说明

  • 三者必须全部匹配:是最严格的场景,需同时满足 action、category、data 的规则。

示例代码

ini 复制代码
<activity android:name=".PaymentActivity">
    <intent-filter>
        <action android:name="com.example.ACTION_PAY" />
        <category android:name="android.intent.category.DEFAULT" />
        <category android:name="com.example.CATEGORY_SECURE" />
        <data android:scheme="alipay" android:host="payment" />
    </intent-filter>
</activity>
scss 复制代码
// 匹配的 Intent
Intent intent = new Intent("com.example.ACTION_PAY");
intent.addCategory("com.example.CATEGORY_SECURE");
intent.setData(Uri.parse("alipay://payment?order=123"));
startActivity(intent);

⚠️ 匹配要点

  • 缺少任意一个 category 或 data 的 Scheme 均失败,例如 http://payment 不匹配 Scheme alipay

💎 总结:四种情况匹配规则对比

配置组合 关键规则
action 必须显式添加 DEFAULT category
action + category Intent 的 category 必须全匹配,且包含 DEFAULT
action + data data 的 URI 和 MIME 需精确匹配,默认 Scheme 为 content/file
action + category + data 三者需同时满足,任何部分不匹配即失败

✅ 最佳实践建议

  1. 防御性匹配检查
    使用 Intent.resolveActivity()PackageManager.queryIntentActivities() 检查是否有匹配组件。
  2. 避免 data 歧义
    显式声明 URI 的 schemehost,避免依赖默认值。
  3. 通配符使用
    pathPattern 支持 * 通配符(如 image_*.jpg),但需转义为 \*

可通过命令 adb shell dumpsys activity activities 查看任务栈验证匹配结果。

⚠️ 四、关键注意事项

  1. 生命周期回调​:

    • 复用 Activity 时(如 singleTop),onNewIntent() 会被调用,需在此方法中更新数据。
  2. 任务栈调试​:

    • 使用 adb shell dumpsys activity activities 查看栈结构。
  3. 跨应用共享​:

    • singleInstance + android:exported="true" 允许外部应用调用。
  4. 隐式启动安全​:

    • 调用前用 resolveActivity() 检查是否存在匹配组件,避免 ActivityNotFoundException

💡 ​最佳实践​:

  • 主界面使用 singleTask 避免多层返回;
  • 频繁跳转页(如通知入口)用 singleTop 减少重复创建;
  • 谨慎使用 singleInstance,避免内存碎片化。
    完整源码示例及调试技巧可参考:CSDN 启动模式详解
相关推荐
千里马学框架1 天前
一起学 Android 14:ShellTransition 屏幕旋转过程深度剖析
android·智能手机·性能优化·framework·性能·屏幕旋转·rotation
美狐美颜SDK开放平台1 天前
开发直播APP时如何接入视频美颜SDK?开发流程与注意事项
android·人工智能·计算机视觉·音视频·直播美颜sdk
AFinalStone1 天前
Android7 SystemUI源码解析(七)Keyguard锁屏模块深度解析
android·systemui
致远ccc1 天前
Google Play 上架前如何测试 App?多国家 Android 环境测试
android·app测试·googleplay·多国家应用测试
ttyyttemo1 天前
Kotlin 协程中的 Job 结构化并发与取消
android
sun0077001 天前
tbox 4g/5g切换,导致wan ip 改变,导致车机旧网络不可用。需要重启车机才行
android
其实防守也摸鱼1 天前
内网穿透与反向代理:原理、工具与实战指南
android·大数据·运维·安全·网络安全·自动化·渗透
AFinalStone2 天前
Android7 SystemUI 源码解析(四)NavigationBar 导航栏与 SystemBars
android·systemui
JMchen2 天前
属性动画原理与高级动画实现
android·kotlin·canvas
AFinalStone2 天前
Android7 SystemUI 源码解析(二)启动流程深度解析
android·systemui