Intent学习

构建 Intent

Intent 对象携带 Android 系统用来确定要启动哪个组件的信息(例如,准确的组件名称或应当接收该 Intent 的组件类别),以及收件人组件为了正确执行操作而使用的信息(例如,要采取的操作以及要处理的数据)。

Intent 中包含的主要信息如下:

组件名称
要启动的组件名称。

这是可选项,但也是构建显式 Intent 的一项重要信息,这意味着 Intent 应当仅传递给由组件名称定义的应用组件。如果没有组件名称,则 Intent 则为隐式,且系统将根据其他 Intent 信息(例如,以下所述的操作、数据和类别)决定哪个组件应当接收 Intent。如需在应用中启动特定的组件,则应指定该组件的名称。

请注意:启动 Service 时,应始终指定组件名称。否则,您无法确定哪项服务会响应 Intent,且用户无法看到哪项服务已启动。

Intent 的这一字段是 ComponentName 对象,您可以使用目标组件的完全限定类名指定此对象,其中包括应用的软件包名称。例如,com.example.ExampleActivity。您可以使用 setComponent()setClass()setClassName(),或 Intent 构造函数设置组件名称。

 

操作
指定要执行的通用操作(例如,查看选取)的字符串。

对于广播 Intent,这是指已发生且正在报告的操作。操作会在很大程度上决定其余 Intent 的构成,特别是数据和 extra 中包含的内容。

您可以指定自己的操作,供 Intent 在您的应用内使用(或者供其他应用在您的应用中调用组件)。但是,您通常应该使用由Intent 类或其他框架类定义的操作常量。以下是一些用于启动 Activity 的常见操作:

ACTION_VIEW
如果您拥有一些某项 Activity 可向用户显示的信息(例如,要使用图库应用查看的照片;或者要使用地图应用查看的地址),请通过 Intent 将此操作与 startActivity() 结合使用。
ACTION_SEND
这也称为共享 Intent。如果您拥有一些用户可通过其他应用(例如,电子邮件应用或社交共享应用)共享的数据,则应使用 Intent 将此操作与 startActivity() 结合使用。

有关更多定义通用操作的常量,请参阅 Intent 类参考文档。其他操作在 Android 框架中的其他位置定义。例如,对于在系统的设置应用中打开特定屏幕的操作,将在 Settings中定义。

您可以使用 setAction() 或 Intent 构造函数为 Intent 指定操作。

如以下示例所示,如果定义自己的操作,请确保加入应用的软件包名称作为前缀:

 
static final String ACTION_TIMETRAVEL = "com.example.action.TIMETRAVEL";
数据
引用待操作数据和/或该数据 MIME 类型的 URI(Uri 对象)。提供的数据类型通常由 Intent 的操作决定。例如,如果操作是 ACTION_EDIT,则数据应包含待编辑文档的 URI。

创建 Intent 时,除了指定 URI 以外,指定数据类型(其 MIME 类型)往往也很重要。例如,能够显示图像的 Activity 可能无法播放音频文件,即便 URI 格式十分类似时也是如此。因此,指定数据的 MIME 类型有助于 Android 系统找到接收 Intent 的最佳组件。但,有时 MIME 类型可以从 URI 中推断得出,特别当数据是 content: URI 时尤其如此。content: URI 表明数据位于设备中,且由 ContentProvider 控制,这使得数据 MIME 类型对系统可见。

要仅设置数据 URI,请调用 setData()。要仅设置 MIME 类型,请调用 setType()。如有必要,您可以使用 setDataAndType() 同时显式设置二者。

注意:若要同时设置 URI 和 MIME 类型,请勿调用 setData() 和 setType(),因为它们会互相抵消彼此的值。请始终使用 setDataAndType() 同时设置 URI 和 MIME 类型。

 

类别
一个包含应处理 Intent 组件类型的附加信息的字符串。您可以将任意数量的类别描述放入一个 Intent 中,但大多数 Intent 均不需要类别。以下是一些常见类别:
CATEGORY_BROWSABLE
目标 Activity 允许本身通过网络浏览器启动,以显示链接引用的数据,如图像或电子邮件。
CATEGORY_LAUNCHER
该 Activity 是任务的初始 Activity,在系统的应用启动器中列出。

有关类别的完整列表,请参阅 Intent 类描述。

您可以使用 addCategory() 指定类别。

以上列出的这些属性(组件名称、操作、数据和类别)表示 Intent 的既定特征。通过读取这些属性,Android 系统能够解析应当启动哪个应用组件。但是,Intent 也有可能会携带一些不影响其如何解析为应用组件的信息。Intent 还可以提供以下信息:

Extra
携带完成请求操作所需的附加信息的键值对。正如某些操作使用特定类型的数据 URI 一样,有些操作也使用特定的 extra。

您可以使用各种 putExtra() 方法添加 extra 数据,每种方法均接受两个参数:键名和值。您还可以创建一个包含所有 extra 数据的 Bundle 对象,然后使用 putExtras() 将 Bundle 插入 Intent 中。

例如,使用 ACTION_SEND 创建用于发送电子邮件的 Intent 时,可以使用 EXTRA_EMAIL 键指定目标收件人,并使用 EXTRA_SUBJECT 键指定主题

Intent 类将为标准化的数据类型指定多个 EXTRA_* 常量。如需声明自己的 extra 键(对于应用接收的 Intent),请确保将应用的软件包名称作为前缀,如下例所示:

 
static final String EXTRA_GIGAWATTS = "com.example.EXTRA_GIGAWATTS";

注意:在发送您希望另一个应用接收的 Intent 时,请勿使用 Parcelable 或 Serializable 数据。如果某个应用尝试访问 Bundle 对象中的数据,但没有对打包或序列化类的访问权限,则系统将提出一个 RuntimeException

标志
标志在 Intent 类中定义,充当 Intent 的元数据。标志可以指示 Android 系统如何启动 Activity(例如,Activity 应属于哪个任务),以及启动之后如何处理(例如,Activity 是否属于最近的 Activity 列表)。

如需了解详细信息,请参阅 setFlags() 方法。

显式 Intent 示例

1. 构造函数

Intent intent = new Intent(FirstActivity.this,SecondActivity.class);
startActivity(intent);

 

2. setClassName

Intent intent = new Intent();
//表示希望启动com.example.test包中的com.example.test.MainActivity
intent.setClassName("com.example.test","com.example.test.MainActivity");
startActivity(intent);

 

3. setClass

Intent intent = new Intent();
//启动packageContext包里的OtherActivity.class类;
intent.setClass(Context packageContext, OtherActivity.class);
startActivity(intent);

 

隐式 Intent示例

复制代码
// Create the text message with a string
Intent sendIntent = new Intent();
sendIntent.setAction(Intent.ACTION_SEND);
sendIntent.putExtra(Intent.EXTRA_TEXT, textMessage);
sendIntent.setType("text/plain");

// Verify that the intent will resolve to an activity
if (sendIntent.resolveActivity(getPackageManager()) != null) {
    startActivity(sendIntent);
}
复制代码

调用 startActivity() 时,系统将检查已安装的所有应用,确定哪些应用能够处理这种 Intent(即:含 ACTION_SEND 操作并携带“text/plain”数据的 Intent)。如果只有一个应用能够处理,则该应用将立即打开并为其提供 Intent。如果多个 Activity 接受 Intent,则系统将显示一个对话框(如图 2 所示),使用户能够选取要使用的应用。

这是Intent的另一个构造函数,直接将action的字符串传进来,表明我们想要启动能够相应com.example.activitytest.ACTION_START这个action的活动。

        button1.setOnClickListener {
            Toast.makeText(this,"You clicked Button1",Toast.LENGTH_SHORT).show()
            val intent = Intent("com.example.activitytest.ACTION_START")
            startActivity(intent)
        }

能启动SecondActivity的原因,是因为SecondActivity的category标签使用的是默认值DEFAULT。在调用 startActivity()时,会自动传入 默认的category。

接收隐式 Intent

要公布应用可以接收哪些隐式 Intent,请在清单文件中使用 <intent-filter> 元素为每个应用组件声明一个或多个 Intent 过滤器。每个 Intent 过滤器均根据 Intent 的操作、数据和类别指定自身接受的 Intent 类型。仅当隐式 Intent 可以通过 Intent 过滤器之一传递时,系统才会将该 Intent 传递给应用组件。

请注意:显式 Intent 始终会传递给其目标,无论组件声明的 Intent 过滤器如何均是如此。

应用组件应当为自身可执行的每个独特作业声明单独的过滤器。例如,图像库应用中的一个 Activity 可能会有两个过滤器,分别用于查看图像和编辑图像。当 Activity 启动时,将检查 Intent 并根据 Intent 中的信息决定具体的行为(例如,是否显示编辑器控件)。

每个 Intent 过滤器均由应用清单文件中的 <intent-filter> 元素定义,并嵌套在相应的应用组件(例如,<activity> 元素)中。在 <intent-filter> 内部,您可以使用以下三个元素中的一个或多个指定要接受的 Intent 类型:

<action>
在 name 属性中,声明接受的 Intent 操作。该值必须是操作的文本字符串值,而不是类常量。
<data>
使用一个或多个指定数据 URI(schemehostportpath)各个方面和 MIME 类型的属性,声明接受的数据类型。
<category>
在 name 属性中,声明接受的 Intent 类别。该值必须是操作的文本字符串值,而不是类常量。

请注意:要接收隐式 Intent,必须将 CATEGORY_DEFAULT 类别包括在 Intent 过滤器中。方法 startActivity() 和 startActivityForResult() 将按照其声明 CATEGORY_DEFAULT 类别的方式处理所有 Intent。如果未在 Intent 过滤器中声明此类别,则隐式 Intent 不会解析为您的 Activity。

例如,以下是一个使用包含 Intent 过滤器的 Activity 声明,当数据类型为文本时,系统将接收 ACTION_SEND Intent :

<activity android:name="ShareActivity">
    <intent-filter>
        <action android:name="android.intent.action.SEND"/>
        <category android:name="android.intent.category.DEFAULT"/>
        <data android:mimeType="text/plain"/>
    </intent-filter>
</activity>

 

向下一个Activity传递数据

Intent不仅可以用来打开其它的Activity,还可以用来进行数据传输。

传输方法很简单,Intent提供了一系列的 putExtra() 方法重载,可以把想要传输的数据暂时封存到Intent中,启动新的Activity后,再从Intent中取出。

打开Activity 时,先将strData存放在了intent中,代码如下:

        button1.setOnClickListener {
            val strData = "Message"
            val intent = Intent(this, SecondActivity::class.java)
            intent.putExtra("extra_name", strData)
            startActivity(intent)
        }

 


取出代码如下,需要在SecondActivity 的 onCreate() 函数中自行取出,代码如下:

class SecondActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.second_layout)
        val extraData = intent.getStringExtra("extra_data")
        Log.d("SecondActivity","extra data is $extraData")
    }
}

 


代码中的intent实际上是调用父类的getIntent()方法,从而来获得启动SecondActivity 的intent。然后调用getStringExtra()方法并传入相应的键值,就可以得到传递的数据了。这里由于我们传递的是字符串,所以使用getStringExtra()方法来获取传递的数据。如果传递的是整型数据,则使用getIntExtra()方法;如果传递的是布尔型数据,则使用getBooleanExtra()方法,以此类推。

向上一个Activity传递数据

由于返回上一个Activity,仅需back即可。没有专门的Intent,并不能像向下传递消息一样。

Activity类提供了一个启动Activity的 startActivityForResult() 方法。

button1.setOnClickListener {
    val intent = Intent(this, SecondActivity::class.java)
    startActivityForResult(intent, 1)
}

 


接下来在SecondActivity中添加点击事件:

        button2.setOnClickListener {
            val intent = Intent()
            intent.putExtra("data_return", "Hello FirstActivity")
            setResult(RESULT_OK, intent)
            finish()
        }

 


着同样创建了一个intent,并没有意图,仅用来进行数据传输。

紧接着把要传递的数据存放在Intent中,然后调用了setResult()方法。这个方法非常重要,专门用于向上一个Activity返回数据。

setResult()方法接收两个参数:

第一个参数用于向上一个Activity返回处理结果,一般只使用RESULT_OK或RESULT_CANCELED这两个值;

第二个参数则把带有数据的Intent传递回去。最后调用了finish()方法来销毁当前Activity。

Tips:当前返回数据是通过SecondActivity中的按钮来返回,但是一般返回上一Activity直接使用back,因此需要另一种写法:

由于我们是使用startActivityForResult()方法来启动SecondActivity的,在SecondActivity被销毁之后会回调上一个Activity的onActivityResult()方法,因此我们需要在FirstActivity中重写这个方法来得到返回的数据,如下所示:

复制代码
    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")
            }
        }
    }
复制代码


onActivityResult()方法带有3个参数:第一个参数requestCode,即我们在启动Activity时传入的请求码;第二个参数resultCode,即我们在返回数据时传入的处理结果;第三个参数data,即携带着返回数据的Intent。由于在一个Activity中有可能调用startActivityForResult()方法去启动很多不同的Activity,每一个Activity返回的数据都会回调到onActivityResult()这个方法中,因此我们首先要做的就是通过检查requestCode的值来判断数据来源。确定数据是从SecondActivity返回的之后,我们再通过resultCode的值来判断处理结果是否成功。最后从data中取值并打印出来,这样就完成了向
上一个Activity返回数据的工作。

但是目前版本已经被Google淘汰,需要使用更新的 Activity Result API,用法如下:

参考
Activity Result API详解,是时候放弃startActivityForResult了_guolin的博客-CSDN博客_startactivityforresult废弃
如果你将项目中的appcompat库升级到1.3.0或更高的版本,你会发现startActivityForResult()方法已经被废弃了。这个方法相信所有做过Android的开发者都用过,它主要是用于在两个Activity之间交换数据的。那么为什么这个如此常用的方法会被废弃呢?官方给出的说法是,现在更加建议使用Activity Result API来实现在两个Activity之间交换数据的功能。我个人的观点是,startActivityForResult()方法并没有什么致命的问题,只是

    private val requestDataLauncher =
        registerForActivityResult(ActivityResultContracts.StartActivityForResult()){
            if (it.resultCode == RESULT_OK) {
                val returnData = it.data?.getStringExtra("data_return")
                Log.d("FirstActivity","data return is $returnData")
            }
        }


通过 registerForActivityResult() 来注册对Activity的结果的监听。

registerForActivityResult()方法接收两个参数:

第一个参数是一种Contract类型,由于我们是希望从另外一个Activity中请求数据,因此这里使用了StartActivityForResult。

第二个参数是一个Lambda表达式,当有结果返回时则会回调到这里,然后我们在这里获取并处理数据即可。

参考:

https://developer.android.google.cn/guide/components/intents-filters

 

posted @   雨潇潇兮  阅读(56)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
点击右上角即可分享
微信分享提示