[Android 从零到一] Intent 与 IntentFilter

1. 背景

Activity 之间怎么通信?答案是 Intent。Intent 是 Android 中连接各组件的「信使」——启动 Activity、发送广播、绑定 Service 都要靠它。而 IntentFilter 决定了哪些 Intent 能被接收。很多新手分不清显式隐式、搞不懂为什么 Intent 发出去没响应,今天说清楚。

2. Intent 是什么

Intent 是一个消息对象,包含要执行的操作和操作涉及的数据。

2.1 核心组成

  • ComponentName — 目标组件(显式)
  • Action — 动作字符串(ACTION_VIEW、ACTION_SEND 等)
  • Data — 操作的数据 URI + MIME 类型
  • Category — 额外分类信息
  • Extras — 携带的附加数据(Bundle)
  • Flags — 控制行为的标志位

3. 显式 Intent vs 隐式 Intent

3.1 显式 Intent

直接指定目标组件,精确查找:

// 方式一:指定类名
startActivity(Intent(this, DetailActivity::class.java))

// 携带数据
val intent = Intent(this, DetailActivity::class.java).apply {
    putExtra("user_id", 1001)
    putExtra("user_name", "小明")
}
startActivity(intent)
// 接收端取值
class DetailActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        val userId = intent.getIntExtra("user_id", -1)
        val userName = intent.getStringExtra("user_name")
    }
}

3.2 隐式 Intent

声明 Action 和 Data,系统根据 IntentFilter 匹配目标:

// 打开网页
startActivity(Intent(Intent.ACTION_VIEW, Uri.parse("https://github.com")))

// 发送文本
val intent = Intent(Intent.ACTION_SEND).apply {
    type = "text/plain"
    putExtra(Intent.EXTRA_TEXT, "分享一段文字")
}
startActivity(Intent.createChooser(intent, "分享到"))

// 拨号
val intent = Intent(Intent.ACTION_DIAL, Uri.parse("tel:10086"))
startActivity(intent)

4. IntentFilter 匹配规则

IntentFilter 是隐式 Intent 的「门牌号」,声明在 AndroidManifest.xml 中:


    
        
        
        
    

4.1 三大匹配规则

规则说明注意点
Action 匹配完全一致(字符串匹配)Filter 可声明多个 action
Category 匹配Intent 所有 category 在 Filter 中有对应项默认带 CATEGORY_DEFAULT,Filter 必须声明
Data 匹配URI + MIME type最容易被忽视的坑

4.2 常见陷阱

// ❌ 这样会匹配失败(缺 CATEGORY_DEFAULT)
val intent = Intent("com.example.ACTION_MY_CUSTOM")
startActivity(intent)

// ✅ 加 CATEGORY_DEFAULT
val intent = Intent("com.example.ACTION_MY_CUSTOM").apply {
    addCategory(Intent.CATEGORY_DEFAULT)
}
startActivity(intent)

5. 踩坑指南

  • ActivityNotFoundException:隐式 Intent 启动前用 intent.resolveActivity(packageManager) 检查
  • FileUriExposedException:Android 7.0+ 禁止 file:// 跨应用共享,用 FileProvider
  • PendingIntent 不可变性:Android 12+ 必须指定 FLAG_IMMUTABLE 或 FLAG_MUTABLE
  • exported 声明:targetSdk 31+ 必须显式设置 android:exported

6. 总结

  1. 显式 Intent — 自己 App 内跳转,精确高效
  2. 隐式 Intent — 跨应用调用,系统匹配 Action+Category+Data
  3. IntentFilter 三要素缺一不可,CATEGORY_DEFAULT 是最大陷阱
posted @ 2026-06-09 11:18  天总会晴的  阅读(3)  评论(0)    收藏  举报