Android Intent与IntentFilter

623 阅读3分钟

显式Intent

在构造Intent时,写死需要跳转的Activity对应的class。

val intent = Intent(this@MainActivity, SecondActivity::class.java)
startActivity(intent)

隐式Intent

不明确指定想要跳转哪个Activity,而是指定了一系列的action和category信息,交由系统找出合适的Activity去启动。

Demo

  1. 给SecondActicity加上intent-filter,分别加上action和category。
<activity
    android:name=".SecondActivity"
    android:exported="true">
    <intent-filter>
        <action android:name=".second" /> <!-- 此处为用户自定义的字符串 !-->
        <category android:name="android.intent.category.DEFAULT" />
    </intent-filter>
</activity>
  1. 在MainActivity跳转时:
val intent = Intent(".second")
startActivity(intent)

添加category

一个Intent中只能指定一个action,但可以指定多个category。

val intent = Intent(".second")
intent.addCategory( ".myCategory" )
startActivity(intent)

此时跳转失败,因为SecondActivity的category是"android.intent.category.DEFAULT",无法找到匹配的category。

如果在SecondActivity中添加该category,即可正常跳转。

<activity
    android:name=".SecondActivity"
    android:exported="true">
    <intent-filter>
        <action android:name=".second" /> <!-- 此处为用户自定义的字符串 -->esa
        <category android:name="android.intent.category.DEFAULT" />
        <category android:name=".myCategory" />
    </intent-filter>
</activity>

打开内置应用——浏览器

使用浏览器打开网址:

val intent = Intent(Intent.ACTION_VIEW)
intent.data = Uri.parse("https://www.baidu.com")
startActivity(intent)

让自己的Activity支持打开https的链接:

<activity
    android:name=".SecondActivity"
    android:exported="true">
    <intent-filter tools:ignore="AppLinkUrlError">
 <action  android:name = "android.intent.action.VIEW" />
 <category  android:name = "android.intent.category.DEFAULT" />
 <data  android:scheme = "https" />
    </intent-filter>
</activity>

此时再通过刚才的intent打开Activity时,就会有一个弹窗提醒所有可以打开url链接的app:

打开内置应用——拨号盘

val intent = Intent(Intent.ACTION_DIAL)
intent.data = Uri.parse("tel:10086")
startActivity(intent)

Activity跳转时携带数据

向下一个Activity传数据

// 将数据写到intent中(MainActivity)
val intent = Intent(this, SecondActivity::class.java)
intent.putExtra("int", 1)
intent.putExtra("bool", false)
intent.putExtra("string", "test")
startActivity(intent)

// 从intent中读数据(SecondActivity)
val intData = intent.getIntExtra("int", 0)
val boolData = intent.getBooleanExtra("bool", false)
val stringData = intent.getStringExtra("string")
Log.d("tag", "$intData, $boolData, $stringData ") // 1, false, test 

返回数据给上一个Activity

// MainAcitivity,注册回调
class MainActivity : AppCompatActivity() {
    // 需在onCreate之前注册!!!
    private val requestLauncher =
        registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
            // 当获取到ACtivity返回的数据后的回调
            if (it.resultCode == RESULT_OK) {
                val intent = it.data as Intent
                val data = intent.getIntExtra("int", 0)
                Log.d("tag", "get result: $data") // get result: 1111
            }
        }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        val binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)

        binding.button.setOnClickListener {
            val intent = Intent(this, SecondActivity::class.java)
            requestLauncher.launch(intent)
        }
    }
}

// SecondActivity,将数据返回给上一个Activity
class SecondActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        val binding = ActivitySecondBinding.inflate(layoutInflater)
        setContentView(binding.root)

        binding.button2.setOnClickListener{
            val response = Intent().apply {
                putExtra("int", 1111)
            }
            setResult(RESULT_OK, response)
            finish()
        }
    }
}

RegisterForActivityResult介绍_chenrenxiang的博客-CSDN博客

registerForActivityResult()_红地毯前吃泡面的博客-CSDN博客

获取 activity 的结果 | Android 开发者 | Android Developers

IntentFilter的匹配规则

  1. 一个Activity可以有多个IntentFilter,一个Intent只要能匹配任何一组IntentFilter,即可成功启动对应的Activity。
  1. 一个IntentFilter中的action、category和data必须同时满足匹配规则,才算匹配成功。
  1. IntentFilter中可以设置action、category和data三种过滤信息,每一种信息都可以有多个。

action的匹配规则

  1. Intent中没有指定action:匹配失败。
  1. Intent中指定了action:一个IntentFilter中只要能找到该action就算匹配成功。
  1. action匹配时区分大小写。

category的匹配规则

  1. Intent中可以不加category:系统会默认添加一个默认的categoryandroid.intent.category.DEFAULT,此时任何IntentFilter都可以匹配成功(IntentFilter中须添加 android.intent.category.DEFAULT)。
  1. Intent中添加了一个或多个category:IntentFilter必须匹配所有的category才算匹配成功。

data的匹配规则

  1. 与action类似,如果IntentFilter中定义了data,那么Intent中必须也要定义可匹配的data。

data的数据结构

data由两部分组成:

  • mimeType:媒体类型(图片、文本、视频等不同的媒体格式)

    • image/jpeg
    • audio/mpeg4-generic
    • video/*
  • URI:资源地址,结构如下:

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

  1. 过滤规则实例:

Demo1

<intent-filter>
    <action android:name=".test"/>
    <category android:name="android.intent.category.DEFAULT" />
    <data android:mimeType="image/*"/>
</intent-filter>

这种规则指定了媒体类型为所有类型的图片,要想匹配这种规则,Intent必须满足:

  • mimeType为image/*
  • URI可以不指定,因为有默认值content和file

为了匹配上述规则,一个intent示例如下:

intent = Intent(".test")
intent.setDataAndType(Uri.parse("file://abc"), "image/png")
// 不可单独使用setData和setType,因为会清除对方的值

Demo2

<intent-filter>
    <action android:name=".test"/>
    <category android:name="android.intent.category.DEFAULT" />
    <data android:mimeType="video/mpeg" android:scheme="http"/>
    <data android:mimeType="audio/mpeg" android:scheme="ftp"/>
</intent-filter>

为了匹配该规则,几个intent示例如下:

intent = Intent(".test")
intent.setDataAndType(Uri.parse("ftp://abc"), "video/mpeg")
// 或者
intent.setDataAndType(Uri.parse("http://abc"), "video/mpeg")
// 或者
intent.setDataAndType(Uri.parse("http://abc"), "audio/mpeg")