Android: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 所包含的信息如下图:
在这里插入图片描述
Intent对象大致包括7大属性:Action(动作)、Data(数据)、Category(类别)、Type(数据类型)、Component(组件)、Extra(扩展信息)、Flag(标志位)。其中最常用的是Action属性和Data属性。

根据信息的作用用于,又可分为三类:

  • 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
在这里插入图片描述
Broadcast Actions:
在这里插入图片描述

2.2、Data:表示与动作要操纵的数据

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="www.baidu.com" 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()方法来设置数据。
在这里插入图片描述

2.7、Flag:期望这个意图的运行模式

用来指示系统如何启动一个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 如何通过系统传递以启动其他 Activity 的图解: [1] Activity A 创建包含操作描述的 Intent,并将其传递给 startActivity()。 [2] Android 系统搜索所有应用中与 Intent 匹配的 Intent 过滤器。 找到匹配项之后, [3] 该系统通过调用匹配 Activity(Activity B)的 onCreate() 方法并将其传递给 Intent,以此启动匹配 Activity。

3.2.1、Intent过滤器

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 具有子元素,其构成如下图:

在这里插入图片描述
在 Intent 中传入的 Uri 对象会被解析成<scheme>://<host>:<port>/<path>(<协议>://<主机名>:<端口>/<路径>)4 个部分进行匹配测试。4 项均为可选,但是存在线性依赖关系:

  • 如果未指定 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":

<activity  
    android:name="com.example.app.SecondActivity">  
    <intent-filter>  
        <action android:name="mark"/>  
        <category android:name="android.intent.category.DEFAULT"/>  
    </intent-filter>  
</activity>  

然后,在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. IntentBundle
    • c. Serializable对象、Parcelable及其对应数组、CharSequence 类型
    • d. ArrayList,泛型参数类型为:<Integer><? Extends Parcelable><Charsequence><String>

在目标组件中取出 Intent 的方法根据数据类型有非常多,这里不一一列举,只给出一般格式。
在这里插入图片描述

3.3.3、具体使用

在当前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、不同组件间 传递数据

  • 13
    点赞
  • 43
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值