Intent的简介:
是Android中用于组件(Activity,Service,BroadcastReceiver,ContentProvider)之间传递信息的对象,相当于组件间通信的”信使“,它不仅能启动目标组件,还能携带数据(如文本,图片,对象等)进行传递
核心作用:
启动组件:打开新的activity(点击按钮跳转到详情页),启动后台service(如下载文件,播放音乐),触发BroadcastReceiver(监听网络变化,电量低提醒)
传递数据:在Activity之间传递参数(如列表想点击后传递ID到详情页),向service传递操作指令(如暂停/播放音乐),在广播中携带状态信息(如网络连接状态变更)
声明组件能力:通过Intent Filter定义组件能相应的Intent类型(如某个Activity可以打开网页连接)
分类:
类型 | 显式 Intent | 隐式 Intent |
---|---|---|
核心特点 | 明确指定目标组件的类名 | 不指定类名,通过动作(Action)、类别(Category)、数据(Data)匹配目标组件 |
使用场景 | 应用内组件跳转(如 Activity 之间) | 跨应用调用(如打开系统相机、浏览器)或应用内解耦(如插件化) |
示例代码 | Intent(this, TargetActivity::class.java) | Intent(Intent.ACTION_VIEW, Uri.parse("https://www.example.com")) |
匹配方式 | 直接根据类名查找,成功率 100% | 系统根据 Intent Filter 匹配,可能匹配多个组件或失败 |
使用显示Intent
Intent的构造函数:其有多个构造函数的重载,其中一个是Intent(Context packageContext, Class<?> cls)。
参数一:Context要求提供一个启动Activity的上下文
参数二:第二个参数Class用于指定想要启动的目标Activity
通过Intent的构造函数可以构建出Intent的意图。
Activity类中提供了一个startActivity()方法,专门用于启动Activity,它接受一个Intent参数。
显示Intent实现Activity跳转
在这我们首先构建了一个Intent对象,
第一个参数传入this也就是FirstActivity作为上下文,
第二 个参数传入SecondActivity::class.java作为目标Activity
注意,Kotlin中 SecondActivity::class.java的写法就相当于Java中SecondActivity.class的写法
来再通过startActivity()方法执行这个Intent就可以
在FirstActivity中设置按钮,然后为按钮设置点击事件,添加后跳转至新的Activity
class MainActivity : AppCompatActivity() { private val TAG = "MainActivity" override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.main_layout) findViewById<Button>(R.id.btn1).setOnClickListener{ val intent = Intent(this,MainActivity1::class.java) startActivity(intent) } Log.d(TAG,"onCreate()方法被执行") } }
按一下Back键就可以销毁当前Activity,从而回到上一个Activity,因为这种方式意图特别明显,所以称为显示Intent
隐式Intent
相比于显式Intent,隐式Intent则含蓄了许多,它并不明确指出想要启动哪一个Activity,而是 指定了一系列更为抽象的action和category等信息,然后交由系统去分析这个Intent,并帮 我们找出合适的Activity去启动。
首先在AndroidManiFest.xml中添加指定当前Activity能够相应的action和category
<activity android:name=".SecondActivity" > <intent-filter> <action android:name="com.example.activitytest.ACTION_START" /> <category android:name="android.intent.category.DEFAULT" /> </intent-filter> </activity>
在<action>标签中我们指明了当前Activity可以响应”com.example.activitytest.ACTION_
START“这个action,而<category>标签则包含了一些附加信息,更精确的指明了当前Activity能够响应的Intent中还可能带有的category,只有<action>和<category>中的内容同时匹配Intent中指定的action和category时,这个Activity才能响应该Intent
修改实现跳转按钮的点击事件,即可完成跳转:
button1.setOnClickListener {
val intent = Intent("com.example.activitytest.ACTION_START")
//为android.intent.category.DEFAULT是一种默认的category,
//在调用startActivity()方法的时候会自动将这个category添加到Intent中
startActivity(intent)
}
若在若在AndroidManifest.xml中.SecondActivity中新增category
<category android:name="com.example.activitytest.MY_CATEGORY"/>
那么也可通过新增的实现跳转
button1.setOnClickListener {
val intent = Intent("com.example.activitytest.ACTION_START")
intent.addCategory("com.example.activitytest.MY_CATEGORY")
startActivity(intent)
}
更多隐式Intent的用法
1.实现Intent传递数据
Intent中提供了一系列putExtra()方法的重载,可以把我们想要传递的数据暂存在Intent中,在启动另一个Activity后,只需要把这些数据从Intent中取出来就可以了。
例如下方FirstActivity中有一个字符串,现在想把这个字符串传递到SecondActivity中。
在FirstActivity中设置按钮,增加监听事件,点击后发送数据
button1.setOnClickListener { val data = "Hello SecondActivity" val intent = Intent(this, SecondActivity::class.java) //参数一:”存储数据的键“ //参数二:”真正传递的数据“ intent.putExtra("extra_data", data) startActivity(intent) }
在SecondActivity中取出数据
class SecondActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.second_layout) //此处实际上调用父类的getIntent()方法,该方法会获取用于启动SecondActivity //然后调用getStringExtra()方法并传入相应的键值,就可以得到传递的数据了 //这里由于我们传递的是字符串,所以使用getStringExtra()方法来获取传 递的数据。 //如果传递的是整型数据,则使用getIntExtra()方法; //如果传递的是布尔型数据, //则使用getBooleanExtra()方法,以此类推。 val extraData = intent.getStringExtra("extra_data") Log.d("SecondActivity","extra data is $extraData") } }
2.销毁Activity(此处后面会做详细介绍)
Android中的Activity是可以层叠的,我们每启动一个新的Activity,就会覆盖在原Activity之上,然后点击Back键会销毁最上面的Activity,下面的一个Activity就会重新显示出来
Android使用任务(task)来管理Activity的,一个任务就是一组存放在栈里的Activity的集合,这个栈也被称为返回栈(back stack).栈是一种先进后出的数据结构,在默认情况下,每当我们启动了一个新的Actvity,它就会在返回栈中入栈,并处于栈顶的位置。而每当我们按下Back键或调用finish()方法去销毁一个Activity时,处于栈顶的Activity就会出栈,前一个入栈的Activity就会重新处于栈顶的位置。系统总是会显示处于栈顶的Activity给用户
3.向上一个Activity返回数据
方式一:startActivityForResult()-------------(已弃用,但是老旧代码依旧使用)
那么我们利用Intent让FirstActivity发送数据给SecondActivity,那么再能不能让SecondActivity发送数据给FirstActivity呢,答案是可以的,Activity类中还有一个用于启动Activity的StartActivityForResult()方法,但它期望在Activity销毁的时候能够返回一个结果给上一个Activity。
startActivityForResult()方法接收两个参数:
参数一:Intent
参数二:请求码(用于在之后的回调中判断数据的来源,只要唯一值)
首先还是通过在FirstActivity中设置按钮,点击后跳转至SecondActivity
button1.setOnClickListener { val intent = Intent(this, SecondActivity::class.java) //改变启动Activity的方法 startActivityForResult(intent, 1) }
然后在SecondActivity中设置发送的数据
class SecondActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.second_layout) button2.setOnClickListener { //将数据存放在Intent中 val intent = Intent() intent.putExtra("data_return", "Hello FirstActivity") //专门用于向上一个Activity返回数据的方法 //参数一:用于向上一个Activity返回处理结果 一般只使用RESULT_OK或RESULT_CANCELED这两个值 //参数二:则把带有数据的Intent传递回去 setResult(RESULT_OK, intent) //销毁当前Activity finish() } } }
如果通过按钮实现返回至FirstActivity,那么实现下方逻辑,在FristActivity中重写方法,
由于在一个Activity中有可能调用 startActivityForResult()方法去启动很多不同的Activity,每一个Activity返回的数据都 会回调到onActivityResult()这个方法中,因此我们首先要做的就是通过检查 requestCode的值来判断数据来源。确定数据是从SecondActivity返回的之后,我们再通过 resultCode的值来判断处理结果是否成功。最后从data中取值并打印出来,这样就完成了向 上一个Activity返回数据的工作。
//参数一:requestCode及我们在启动Activity时传入的请求码
//参数二:resultCode 即我们在返回数据时传入的处理结果
//参数三: data 即携带着返回数据的Intent
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
when(requestCode){
1 ->if(resultCode == RESULT_OK){
val returnedData = data?.getStringExtra("data_return")
Log.d("FirstActivity","returned data is $returnedData")
}
}
}
如果通过手机的back键(返回键)实现返回至FirstActivity,那么实现下方逻辑,在FristActivity中重写方法,
override fun onBackPressed() {
val intent = Intent()
intent.putExtra("data_return", "Hello FirstActivity")
setResult(RESULT_OK, intent)
finish()
}
方式二:使用 Activity Result API -------------------新代码推荐
这是现在新代码推荐的方式;
1. FirstActivity(启动方)
class FirstActivity : AppCompatActivity() { // 1. 注册Activity Result Launcher private val startSecondActivity = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result -> if (result.resultCode == RESULT_OK) { // 3. 处理返回的数据 val data = result.data val message = data?.getStringExtra("message") ?: "" Toast.makeText(this, "接收到: $message", Toast.LENGTH_SHORT).show() } } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_first) // 2. 启动SecondActivity findViewById<Button>(R.id.btn_start_second).setOnClickListener { val intent = Intent(this, SecondActivity::class.java) startSecondActivity.launch(intent) } } }
2. SecondActivity(返回数据方)
class SecondActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_second) // 设置返回数据并关闭 findViewById<Button>(R.id.btn_return_data).setOnClickListener { val returnIntent = Intent() returnIntent.putExtra("message", "来自SecondActivity的数据") setResult(RESULT_OK, returnIntent) finish() } // 取消操作 findViewById<Button>(R.id.btn_cancel).setOnClickListener { setResult(RESULT_CANCELED) finish() } } }
4.利用Intent跳转打开浏览器
使用隐式Intent,不仅可以启动自己程序内的Activity,还可以启动其他程序的Activity,这就 使多个应用程序之间的功能共享成为了可能。比如你的应用程序中需要展示一个网页,这时你 没有必要自己去实现一个浏览器(事实上也不太可能),只需要调用系统的浏览器来打开这个 网页就行了。
button1.setOnClickListener { //指定Intent的action为Intent.ACTION_VIEW //这是一个Android系统内置的动作,其常量值为android.intent.action.VIEW val intent = Intent(Intent.ACTION_VIEW) //通过Uri.parse()方法将一个网址字符串解析成一个Uri对象 //再调用Intent的setData()方法将这个Uri对象传递进去 intent.data = Uri.parse("https://www.baidu.com") startActivity(intent) }
还可以在<intent-filter>标签中再配置一个<data>标签,用于更精确地指 定当前Activity能够响应的数据。<data>标签中主要可以配置以下内容。
android:scheme用于指定数据的协议部分,如上例中的https部分。
android:host用于指定数据的主机名部分,如上例中的www.baidu.com部分。
android:port用于指定数据的端口部分,一般紧随在主机名之后。
android:path用于指定主机名和端口之后的部分,如一段网址中跟在域名之后的内
容。
android:mimeType用于指定可以处理的数据类型,允许使用通配符的方式进行指定。
只有当<data>标签中指定的内容和Intent中携带的Data完全一致时,当前Activity才能够响应 该Intent。
<activity android:name=".ThirdActivity"> <intent-filter tools:ignore="AppLinkUrlError"> //配置当前能够响应的action为Intent。ACTION_VIEW常量值 <action android:name="android.intent.action.VIEW" /> //指定默认的category值 <category android:name="android.intent.category.DEFAULT" /> //指定了数据的协议必须时https协议 <data android:scheme="https" /> </intent-filter> </activity
另外,由于Android Studio认为所有能够响应ACTION_VIEW的Activity都应该加上BROWSABLE的category,否 则就会给出一段警告提醒。加上BROWSABLE的category是为了实现deep link功能,和我们 目前学习的东西无关,所以这里直接在<intent-filter>标签上使用tools:ignore属性将 警告忽略即可
5.利用Intent跳转拨打电话
button1.setOnClickListener { val intent = Intent(Intent.ACTION_DIAL) intent.data = Uri.parse("tel:10086") startActivity(intent) }
首先指定了Intent的action是Intent.ACTION_DIAL,这又是一个Android系统的内置动 作。然后在data部分指定了协议是tel,号码是10086