阅读: 6 发表于 2024-08-28 20:01
Intent的理解和使用
Intent的理解和使用 1、什么是Intent
Intent的中文意思是“意图,意向”,在Android中提供了Intent机制来协助应用间的交互与通讯,Intent负责对应用中一次操作的动 作、动作涉及数据、附加数据进行描述,Android则根据此Intent的描述,负责找到对应的组件,将 Intent传递给调用的组件,并完成组件的调用。Intent不仅可用于应用程序之间,也可用于应用程序内部的Activity/Service之间的 交互。因此,可以将Intent理解为不同组件之间通信的“媒介”专门提供组件互相调用的相关信息。
总之,Intent具有激活组件和携带数据的功能!
启动三大组件
下面是Intent启动不同组件的部分方法:
Activity组件 startActivity(Intent intent); startActivityForResult(Intent intent,int requestCode); Service组件: startService(Intent intent); bindService(Intent intent,ServiceConnection conn,int flags); BroadcastReceiver组件: sendBroadcast(Intent intent); sendOrderedBroadcast(Intent intent,String receiverPermission); 2、Intent的构成Intent 作为一个负责组件间传递消息的信息对象,最重要的就是其包含的信息。实际上无论是显式还是隐式,Intent 发出的时候,系统对应的行为正是由 Intent 所包含信息的组合决定。一个 Intent 所包含的信息如下图:
根据信息的作用用于,又可分为三类:
1、Component Name、Action、Data、Category
这4中信息决定了Android会启动哪个组件,其中Component Name用于在显式Intent中使用,Action、Data、Category、Extras、Flags用于在隐式Intent中使用。
2、Extras:里面包含了具体的用于组件实际处理的数据信息。
3、Flags:其是Intent的元数据,决定了Android对其操作的一些行为。
2.1、Action:用来表现意图的行动一个字符串变量,可以用来指定Intent要执行的动作类别。比如查看或选择,其对应着Intent Filter中的action标签。
<intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter>常见的action有:
Activity Actions
Intent中的data指的是Uri对象和数据的MIME类型,其对应着Intent Filter中的data标签。
一个完整的Uri由scheme、host、port、path组成,格式是<scheme>://<host>:<port>/<path>
例如:
content://com.example.project:200/folder/subfolder/etc。Uri就像一个数据链接,组件可以根据此Uri获得最终的数据来源。通常将Uri和action结合使用,比如我们将action设置为ACTION_VIEW,我们应该提供将要被编辑修改的文档的Uri。
2.3、Category:用来表现动作的类别一个包含Intent额外信息的字符串,表示哪种类型的组件来处理这个Intent。任何数量的Category 描述都可以添加到Intent中,但是很多intent不需要category,下面列举一些常用的category:
<!-- 必须指定CATEGORY_DEFAULT,只有这样startActivity(intent)才能找到 --> <category android:name="com.baidu.category.TEST" /> <category android:name="android.intent.category.DEFAULT" /> 2.4、Type:指定数据类型一般Intent的数据类型能够根据数据本身进行判定,但是通过设置这个属性,可以强制采用显式指定的类型而不再进行推导。
intent.setDataAndType(Uri.parse("baidu://www.baidu.com/news"), "image/jpeg"); <data android:mimeType="image/*" android:scheme="baidu" android:host="" android:path="/news"/> 2.5、Component:目的组件指定Intent的目标组件名称,当指定了这个属性后,系统将跳过匹配其他属性,而直接匹配这个属性来启动对应的组件
通过这个方法建立一个Intent对象,然后将该对象传递给Activity的startActivity(Intent intent)方法即可启动目标组件,实例代码如下:
Intent intent = new Intent(this,Activity02.class); //创建Intent对象 startActivity(intent); //开启Activity02 2.6、Extra:扩展信息Intent可以携带的额外 key-value 数据,你可以通过调用putExtra()方法设置数据,每一个 key对应一个 value数据。你也可以通过创建 Bundle对象来存储所有数据,然后通过调用putExtras()方法来设置数据。
用来指示系统如何启动一个Activity,可以通过setFlags()或者addFlags()可以把标签flag用在Intent中。
3、Intent的用法 3.1、显式Intent显式 Intent 通常应用在自己的程序中,启动特定组件。用法比较简单,就是构造一个带有目标组件名的 Intent,作为参数传入上述方法即可,调用方法后会直接启动相应组件。
1)构造方法传入Component,最常用的方式:
Intent intent = new Intent(this, SecondActivity.class); startActivity(intent);2)setComponent方法
Intent intent = new Intent(); intent.setClass(this, SecondActivity.class); //或者intent.setClassName(this, "com.example.app.SecondActivity"); //或者intent.setClassName(this.getPackageName(),"com.example.app.SecondActivity"); startActivity(intent);3)setClass / setClassName方法
Intent intent = new Intent(); intent.setClass(this, SecondActivity.class); //或者intent.setClassName(this, "com.example.app.SecondActivity"); //或者intent.setClassName(this.getPackageName(),"com.example.app.SecondActivity"); startActivity(intent);显式Intent通过Component可以直接设置需要调用的Activity类,可以唯一确定一个Activity,意图特别明确,所以是显式的。设置这个类的方式可以是Class对象(如SecondActivity.class),也可以是包名加类名的字符串(如"com.example.app.SecondActivity")。
3.2、隐式Intent隐式 Intent 允许启动其他应用中的组件,在调用发送 Intent 的方法后,该 Intent 会交由 Android 系统进行匹配,(匹配根据信息是 action、data、category 这3项,即本文第一张图片 Intent 包含信息中标蓝色部分)筛选出整个设备可响应该 Intent 的组件。下图官方文档对隐式 Intent 如何传递启动其他应用组件的图解:筛选是根据所有的<intent-filter>来筛选。
Intent 过滤器是 manifests 里组件的子标签,一个控件可以声明一个或者多个 Intent 过滤器,只要其中一个通过匹配,该组件就可以相应相应 Intent。先来看一个官方给出的 Intent 过滤器示例:
<activity android:name="MainActivity"> <!-- 应用的首页面,会显示在启动器中 --> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <activity android:name="ShareActivity"> <!-- 该活动可以处理 SEND这个 aciton,且处理数据类型为无格式文本 --> <intent-filter> <action android:name="android.intent.action.SEND"/> <!--需要响应隐式Intent的活动必须添加 android.intent.category.DEFAULT这个分类,因为starActivity()方法会默认为Intent添加--> <category android:name="android.intent.category.DEFAULT"/> <data android:mimeType="text/plain"/> </intent-filter> <!-- 此为同一个 Activity 的第二个过滤器 该活动可以处理 "SEND" 和 "SEND_MULTIPLE"两种 aciton 处理数据类型为多媒体数据(包括图片、视频和全景照片) --> <intent-filter> <action android:name="android.intent.action.SEND"/> <action android:name="android.intent.action.SEND_MULTIPLE"/> <category android:name="android.intent.category.DEFAULT"/> <data android:mimeType="application/vnd.google.panorama360+jpg"/> <data android:mimeType="image/*"/> <data android:mimeType="video/*"/> </intent-filter> </activity>这里值得注意的几个点:
1、 Intent 只能有1个 action,而 Intent 过滤器可有多个 action
2、需要响应隐式 Intent 的 Activity 的 Intent 过滤器中必须添加android.intent.category.DEFAULT这个分类
3、 data 在构造时传入的是 Uri 对象以及 mimeType 字符串,mimeType 的对应关系比较直观不详述,Uri对象会被分为 4个部分<scheme>://<host>:<port>/<path>(<协议>://<主机名>:<端口>/<路径>),在 Intent过滤器中的写法如下:
<intent-filter> <data android:scheme="content" android:host="com.example.project" android:port="200" android:path="/folder/subfolder/etc"/> </intent-filter>对应的Uri对象:
Uri uri=Uri.parse("content://com.example.project:200/folder/subfolder/etc");4、 path 和 mimeType 允许使用*通配符,实现部分匹配。
5、对于所有 Activity,必须在清单文件中声明 Intent 过滤器。
但是,广播接收器的过滤器可以通过调用 registerReceiver() 动态注册。 且可以使用 unregisterReceiver() 注销该接收器。这样一来,应用便可仅在应用运行时的某一指定时间段内侦听特定的广播。
匹配规则
隐式 Intent 会与所有设备所有应用组件的 Intent 过滤器进行比对。
一个组件可以有多个 Intent 过滤器,某个 Intent 只需与其中任何一个匹配即可启动组件。
系统会根据 Intent 与 Intent 过滤器的 action、data、category 进行三次比对(测试),要全部通过才能匹配。
action 的匹配规则:
A、Intent 只能包含一项 action,而 Intent 过滤器可以包含多项 action,只要 Intent 的 action 可以在 Intent 过滤器中找到对应项即可通过测试。
B、当 Intent 过滤器未声明任何 action 时,任何 Intent 都不能通过匹配。
C、当 Intent 未指定 Action 时,无法通过匹配。
category 的匹配规则:
A、Intent 可以包含多项 category,Intent 过滤器也可以包含多项 category。Intent 中的每项 category 必须在Intent过滤器中都有对应项,才能通过匹配。
B、当目标组件为 Activity 时,如需相应隐式 Intent,必须添加 “android.intent.category.DEFAULT” 到 Intent 过滤器中。因为启动Activity的方法都会默认为Intent添加该 category。
C、目标组件为广播时,Intent 和 Intent 过滤器都不设置 category,可通过匹配。
data的匹配规则:
和上面两个元素不同,data 具有子元素,其构成如下图:
如果未指定 scheme,则会忽略 host;
如果未指定 host,则会忽略 port;
如果未指定 scheme 和 host,则会忽略 path。
data 的匹配规则主要有以下几点:
A、将 Intent 中的 URI 与过滤器中的 URI 规范进行比较时,它仅与过滤器中包含的部分 URI 进行比较。 例如:
如果过滤器仅指定 scheme,则具有该 scheme 的所有 URI 均与该过滤器匹配。
如果过滤器指定 scheme 和 host,但未指定 path,则具有相同 scheme 和 host 的所有 URI
都会通过过滤器,无论其 path 如何均是如此。
如果过滤器指定 scheme、host和path,则仅具有相同 scheme、host 和 path 的 URI 才会通过过滤器。
path 部分可以使用*通配符,仅需部分匹配路径名即可。
B、mimeType 可以部分使用通配符,如:image/(表示匹配所有格式图像数据),也可以全部使用/* 表示匹配所有类型数据。
C、当Intent同时不指定 uri 与 mimeType 时,只有同样未声明 uri 与 mimeType 的 Intent 过滤器可以通过匹配。
D、当 Intent 只含有 uri 时,只有声明 uri 相互匹配,且未声明 mimeType 的 Intent 过滤器可以通过匹配。
E、当 Intent 只含有 mimeType 时,只有 mimeType 相互匹配,且未声明 uri 的 Intent 过滤器可以通过匹配。
F、当 Intent 同时含有 uri 和 mimeType 时,只有两部分均匹配的 Intent 过滤器可以通过匹配。
G、Intent过滤器只声明mimeType时,默认支持scheme为content: 和 file: 的uri。
H、当 Intent 传入的 uri 为 content: URI 时,表明数据位于设备中,且由 ContentProvider 控制,此时即使不设置 mimeType,mimeType 也对系统可见。
非空判断
当隐式 Intent 发出而找不到匹配 Activity 时,调用将会失败,且应用会崩溃。要验证是否存在会接收 Intent 的 Activity ,可以对 Intent 对象调用 resolveActivity()。如果结果为非空,则至少有一个应用能够处理该 Intent,且可以安全调用 startActivity()。 如果结果为空,则不应使用该 Intent,应停用发出该 Intent 的功能。
Intent sendIntent = new Intent(); sendIntent.setAction(Intent.ACTION_SEND); sendIntent.putExtra(Intent.EXTRA_TEXT, textMessage); sendIntent.setType("text/plain"); // 判断是否存在能够匹配该 Intent 的 Activity if (sendIntent.resolveActivity(getPackageManager()) != null) { startActivity(sendIntent); } 3.2.2、举例下面以Action为例:
AndroidManifest.xml文件中,首先被调用的Activity要有一个带有<intent-filter>并且包含的Activity,设定它能处理的Intent,并且category设为"android.intent.category.DEFAULT"。action的name是一个字符串,可以自定义,例如这里设成为"mark":
然后,在MainActivity,才可以通过这个action name找到上面的Activity。下面两种方式分别通过setAction和构造方法方法设置Action,两种方式效果相同。
1)setAction方法
Intent intent = new Intent(); intent.setAction("mark"); startActivity(intent);2)构造方法直接设置Action
Intent intent = new Intent("mark"); startActivity(intent);为了防止应用程序之间互相影响,一般命名方式是包名+Action名,例如这里命名"mark"就很不合理了,就应该改成"com.example.app.Test"。
3.3、数据传送Intent 作为组件间的信息对象,另一个主要作用就是数据的传送。
3.3.1、使用方法putExtra()、Bundle方式
3.3.2、可传递的数据类型Intent传送数据是以键值对的形式,主要通过putExtra()方法,该方法接收两个参数
第一个是数据的键,第二个是数据的值。
第二个参数的取值范围:
a. 8种基本数据类型(boolean byte char short int long float double)、String
b. Intent、Bundle
c. Serializable对象、Parcelable及其对应数组、CharSequence 类型
d. ArrayList,泛型参数类型为:<Integer>、<? Extends Parcelable>、<Charsequence>、<String>
在目标组件中取出 Intent 的方法根据数据类型有非常多,这里不一一列举,只给出一般格式。
在当前Activity把要传递的数据暂存在Intent中、在新启动的Activity中取出Intent中的数据
方法1:putExtra()
// 目的:将FristActivity中的一个字符串传递到SecondActivity中,并在SecondActivity中将Intent对象中的数据(FristActivity传递过来的数据)取出 // 1. 数据传递 // a. 创建Intent对象(显示Intent) Intent intent = new Intent(FirstActivity.this,SecondActivity.class); // b. 通过putExtra()方法传递一个字符串到SecondActivity; // putExtra()方法接收两个参数:第一个是键,第二个是值(代表真正要传递的数据) intent.putExtra("data","I come from FirstActivity"); // c. 启动Activity startActivity(intent); // 2. 数据取出(在被启动的Activity中) // a. 获取用于启动SecondActivit的Intent Intent intent = getIntent(); // b. 调用getStringExtra(),传入相应的键名,就可得到传来的数据 // 注意数据类型 与 传入时保持一致 String data = intent.getStringExtra("data");方法2:Bundle
// 1. 数据传递 // a. 创建Intent对象(显示Intent) Intent intent = new Intent(FirstActivity.this,SecondActivity.class); // b. 创建bundle对象 Bundle bundle = new Bundle(); // c. 放入数据到Bundle bundle.putString("name", "carson"); bundle.putInt("age", 28); // d. 将Bundle放入到Intent中 intent.putExtras(bundle); // e. 启动Activity startActivity(intent); // 2. 数据取出(在被启动的Activity中) // a. 获取用于启动SecondActivit的Intent Intent intent = getIntent(); // b. 通过Intent获取bundle Bundle bundle = intent.getExtras(); // c. 通过bundle获取数据传入相应的键名,就可得到传来的数据 // 注意数据类型 与 传入时保持一致 String nameString = bundle.getString("name"); int age = bundle.getInt("age");两种方式的区别
Bundle 意为 捆绑 的意思,更多适用于:
连续传递数据
若需实现连续传递:Activity A -> B -> C;
若使用putExtra(),则需写两次intent , A->B先写一遍,在B中取出来 ,再把值重新写到Intent,再跳到C;
若使用 Bundle,则只需取出 & 传入 Bundle对象即可
可传递的值:对象
putExtra()无法传递对象,而 Bundle则可通过 putSerializable传递对象
但传递的对象要实现Serializable接口
// 如传递User类的对象 public class User implements Serializable { ... } // 传递时 User user = new User(); Intent intent = new Intent(MyActivity.this,OthereActivity.class); Bundle bundle = new Bundle(); bundle.putSerializable("user", user); intent.putExtras(bundle);而 putExtra()更多使用于单次传递、传递简单数据类型的应用场景
更多使用
//Activity间的数据传递 // 1.直接向intent对象中传入键值对(相当于Intent对象具有Map键值对功能) intent.putExtra("first", text1.getText().toString()); intent.putExtra("second", text2.getText().toString()); // 2.新建一个Bundle对象 ,想该对象中加入键值对,然后将该对象加入intent中 Bundle bundle = new Bundle(); bundle.putString("first", "zhang"); bundle.putInt("age", 20); intent.putExtras(bundle); // 3.向intent中添加ArrayList集合对象 intent.putIntegerArrayListExtra(name, value); intent.putIntegerArrayListExtra(name, value); // 4.intent传递Object对象(被传递的对象的类实现Parcelable接口,或者实现Serialiable接口) public Intent putExtra(String name, Serializable value) public Intent putExtra(String name, Parcelable value)数据回传
把数据传回上个活动也是 Intent 比较常用的方法之一。
实现的方式是在启动活动时使用startActivityForResult(Intent intent,int requestCode)代替startActivity(Intent intent),当被启动活动销毁时,就会携带一个 Intent 回调到调用startActivityForResult()方法的Activity的startActivityForResult() 方法。关于 Intent 添加 Extra,和数据的取出和普通的用法并没有什么区别。
基本的步骤是:
A、调用startActivityForResult()方法启动新 Activity,该方法有两个参数,参 1 为 Intent,参 2为 int 类型的唯一请求码,用于判断数据来源。
B、在新 Activity 中调用setResult()方法把携带希望回传数据的 Intent 作为参数传入。
C、重写原 Activity 的onActivityResult() 方法。该方法携带 3 个参数,参 1 为启动 Activity的请求码 requestCode,参 2 为表示处理结果是否成功的 resultCode,参 3 为携带数据的 Intent。
重写的主要逻辑是:先通过 requestCode 判断数据来源(根据场景,原 Activity 可能启动不同新 Activity);然后通过 resultCode 判断处理结果是否成功;最后取出 Intent 中数据进行处理即可。
//原 Activity 中启动新 Activity 并请求返回数据 Intent intent = new Intent(this,TagerActivity.class); startActivityForResult(intent,1); ------------------------------------ //新 Activity 中设定返回 Intent 并销毁,销毁后会回调到原 Activity 的 onActivityResult()方法 Intent intent=new Intent(); intent.putExtra("extra_boolean",true); setResult(RESULT_OK,intent); finish(); ------------------------------------ //原 Activity 中重写 onActivityResult() 方法 @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { switch (requestCode){ case 1: if (resultCode==RESULT_OK){ boolean b=data.getBooleanExtra("extra_boolean",false); } break; default: } } 4、Intent常见应用(转)Intent的详细解析以及用法
参考1、https://blog.csdn.net/qq_37567866/article/details/80565042
2、https://www.jianshu.com/p/67d99a82509b
3、https://www.jianshu.com/p/19147a69e970
4、https://www.jianshu.com/p/19147a69e970
5、不同组件间 传递数据