Android Intent 基础

Android Studio基础项目-两个Activity的Intent基本传值。配置运行安卓版本,去除深蓝色按钮,全屏展示APP运行。 Android Studio基础-Intent基本传值 环境准备,新建空的ACTIVTY。配置运行安卓版本,去除深颜色按钮,全屏展示APP运行。 Theme.MaterialComponents.DayNight.Bridge 全屏 android:theme="@style/Theme.Design.NoActionBar" 第一步:设置两个布局XML进行跳转 <?xml version="1.0" encoding="utf-8"?> <LinearLa 阅读详情

Android Intent完全解析

在本篇博客中会涉及以下内容:

  • Intent的概念和使用解析
  • Intent的创建以及Action、Category、Data的解析
  • 显式意图和隐式意图
  • IntentFilter的概念和使用(匹配规则)
  • Deep Link 和App Link

Intent概念和使用

Intent 即为意图,可以用来启动一个Activity,可以用来发送一个广播,启动或者绑定一个服务。最典型最常见的用法就是启动一个Activity,可以把Intent看作各个Activity之间的粘合剂。Intent对将来要发生的行为进行了抽象的描述,然后在运行时进行绑定,这种描述和绑定主要依赖于Intent中保存的数据。比如它保存了某个Activity的类名,那么在之后通过startActivity(Intent)就可以在运行时根据Intent中设置的类名找到并启动该Activity,或者他保存了Intent代表的行为,行为的类别,以及要处理的数据和数据的格式,系统也将根据这些内容以及系统内所有应用的清单文件解析出可以处理该Intent的Activity,并将Intent传递给该Activity。

Intent的主要用途在以下三个方面:

启动 Activity:

Activity 表示应用中的一个页面。通过将 Intent 传递给 startActivity(),您可以启动新的 Activity 实例。Intent 描述了要启动的 Activity,并携带了任何必要的数据。

如果您希望在 Activity 完成后收到结果,请调用 startActivityForResult()。在 Activity 的 onActivityResult() 回调中,您的 Activity 将结果作为单独的 Intent 对象接收。

启动服务:

Service 是一个不使用用户界面而在后台执行操作的组件。通过将 Intent 传递给 startService(),您可以启动服务执行一次性操作(例如,下载文件)。Intent 描述了要启动的服务,并携带了任何必要的数据。

如果服务旨在使用客户端-服务器接口,则通过将 Intent 传递给 bindService(),您可以从其他组件绑定到此服务。

传递广播:

广播是任何应用均可接收的消息。系统将针对系统事件(例如:系统启动或设备开始充电时)传递各种广播。通过将 Intent 传递给 sendBroadcast()、sendOrderedBroadcast() 或 sendStickyBroadcast(),您可以将广播传递给其他应用。

startActivity(intent);//用于启动一个活动
startService(intent);bindService(intent)//用于开启一个服务,只能使用显示意图
sendBroadcast(intent);//发送一个广播
//startActivity,startService,sendBroadcast指明了要开启一个活动或者是启动服务等

Intent的创建和参数说明

Intent的创建

我们可以使用Intent的构造函数创建一个Intent对象,然后根据自己的需求配置合适的参数。

// 这是一个显示Intent,action、category、data不能影响组件的选择,
// 所以这种情况下这些参数一般也不会去设置
// 但是可以设置一些extra参数供下个页面使用。
// 整体上,下面的代码打开一个应用内名为HaveBothActivity.class的页面
Intent intent = new Intent(MainActivity.this,HaveBothActivity.class);
intent.putExtra("userName","francis.fan");
intent.putExtra("userAvatar","http://www.null.com/user/avatar/36271.jpg")
startActivity(intent);

// 下面的这个是隐式的Intent,
// 通过设置Action,告诉系统该Intent想要做什么类型的工作(这里是打开拨号界面)
// 通过设置Data,告诉系统要操作的参数是什么(这里是某个人的手机号)
// 整体上,下面的代码打开了系统的拨号界面,并且打开时已经填入了号码
Intent intent = new Intent();
intent.setAction(Intent.ACTION_DIAL);
intent.setData(Uri.parse("tel:180****8692"));
startActivity(intent);

// 下面的这个是隐式的Intent,
// 通过设置Action,告诉系统该Intent想要做什么类型的工作(这里是要做选择某一种东西的工作)
// 通过设置mimeType,告诉系统要选择的东西的类型(这里是选择皂片)
// 整体上,下面的代码会打开手机内的某一个应用的选择图片的页面(可能有多个这样的,这时候需要用户手动选择一个)
Intent intent = new Intent();
intent.setAction(Intent.ACTION_PICK);
intent.setType("image/*");
startActivityForResult(intent,2);

// 用于在手机Web浏览器上检索数据,也设置了搜索的关键字
Intent intent = new Intent();
intent.setAction(Intent.ACTION_WEB_SEARCH);
intent.putExtra(SearchManager.QUERY,"api player 的博客");
startActivity(intent);

// 用于发送一条数据,数据的接收方会有很多,由用户选择使用哪一种
// 下面的内容设置包含了主题,标题,正文,附件,邮件接收人以及发送内容的mimeType信息在内的多种信息,但是发送的并不一定是邮件,用户也可以选择其他的应用。
Intent intent = new Intent();
intent.setAction(Intent.ACTION_SEND);
intent.putExtra(Intent.EXTRA_EMAIL,new String[]{"francis.fanfan@test.com","645534173@qq.com"});//邮件的收件人
intent.putExtra(Intent.EXTRA_CC,new String[]{"apilpayer@nullpointer.com"});//邮件的抄送人
intent.putExtra(Intent.EXTRA_TEXT,"这是发送的内容的正文部分");
intent.putExtra(Intent.EXTRA_STREAM,imageUri);//这是发送的内容的附件
intent.putExtra(Intent.EXTRA_TITLE,"这是一个标题");
intent.putExtra(Intent.EXTRA_SUBJECT,"分享的主题");
intent.setType("image/*");//指明发送的数据的类型
startActivity(intent);

Intent的参数说明

intent中参数包含了Action,Category,Data(Uri+mimeType), ComponentName,Flag以及Extras等信息。

ComponentName决定有哪个应用的哪个组件来完成该项工作;
通过setAction告知隐式意图的基本行为;
通过addCategory为意图添加分类;
通过setData,setType或者setDataAndType告诉系统要处理的数据和处理数据的类型;
通过putExtra,将数据存在 Bundl e中,通过Intent传递给处理该意图的组件;

//intent中的变量
private String mAction;//Action
private Uri mData;//Data
private String mType;//Type
private ComponentName mComponent;//classname
private int mFlags;//
private ArraySet<String> mCategories;//Category
private Bundle mExtras;//Bundle

下面针对各个参数做下说明:

Action解析

意图的一般性行为,通过设置此参数告诉系统我们的隐式Intent想要的操作是大致是做什么的,是查看数据,搜索或者是编辑,选择数据等。如:

Activity的标准Action:
  • ACTION_MAIN 一个应用的主入口
  • ACTION_VIEW 用于向用户展示数据
  • ACTION_ATTACH_DATA 用于添加数据,比如把一张照片添加给联系人,或者把一段文字添加给一篇笔记上
  • ACTION_EDIT 用于编辑数据,比如编辑图片
  • ACTION_PICK 用于选择数据(比如常见的相册选择照片)
  • ACTION_CHOOSER 提供一个用于某一个Intent的应用选择器
  • ACTION_GET_CONTENT 用于选择一项内容,不需要指定选择项的来源,还有很多其他的细节可以参考文档
  • ACTION_DIAL 打开拨号页面,并填入Data中设置的电话号码,然后由用户选择是否拨打该电话
  • ACTION_CALL 直接开始拨打一个Data中设定的电话号码,6.0以上需要权限,不建议使用
  • ACTION_SEND用于发送/传送数据(分享功能)
  • ACTION_SENDTO 用于发送一条数据对方,可以通过Data确定发送的途径,如 “sms: 180****6680” 确定使用短信发送,其他和 ACTION_SEND 一样。
  • ACTION_ANSWER 处理来电
  • ACTION_INSERT Insert an empty item into the given container.
  • ACTION_DELETE Delete the given data from its container.
  • ACTION_RUN Run the data, whatever that means.
  • ACTION_SYNC Perform a data synchronization.
  • ACTION_PICK_ACTIVITY 用于选择用于某一个Intent的Activity,返回值是一个componentName,可以根据自己的需要做点什么
  • ACTION_SEARCH 用于检索数据,搜索参数放入Extras中,key值使用SearchManager.QUERY
  • ACTION_WEB_SEARCH 使用web浏览器进行搜索,搜索参数放入Extras中,key值使用SearchManager.QUERY
  • ACTION_FACTORY_TEST 工厂测试模式使用
BroadCast的标准Action:

还有两个特别的Action值得注意:

  • android.intent.action.PICK_ACTIVITY 用于选择用于某一个Intent的Activity,返回值是一个componentName,可以根据自己的需要做点什么
  • android.intent.action.CHOOSER 提供一个用于某一个Intent的应用选择器,可以避免直接选择默认应用。

// 这是一个选择照片的隐式Intent
Intent intent = new Intent();
intent.setAction(Intent.ACTION_PICK);
intent.setType("image/*");

// 打开一个能和上面的Intent匹配的所有应用的页面的一个列表页
Intent chooseIntent = new Intent();
chooseIntent.setAction(Intent.ACTION_PICK_ACTIVITY);
chooseIntent.putExtra(Intent.EXTRA_INTENT, intent);
startActivityForResult(chooseIntent, 2);
// 返回值是一个ComponentName,在onActivityResult中接受并处理,可直接用于显式启动
ComponentName componentName = data.getComponent();
startActivityForResult(new Intent().setComponent(componentName), 4);

// 打开一个带标题的应用选择器,和上面的类似,区别是这次打开之后用户选择之后就直接打开应用了,
// 如果EXTRA_INTENT需要返回值,需要使用startActivityForResult,否则直接使用startActivity即可
Intent chooseIntent = new Intent();
chooseIntent.setAction(Intent.ACTION_CHOOSER);
chooseIntent.putExtra(Intent.EXTRA_INTENT,intent);
chooseIntent.putExtra(Intent.EXTRA_TITLE,"选择要打开的应用");
startActivityForResult(chooseIntent,8);
Data解析

data分为两部分:Uri和mimeType.

  • Uri:scheme://host:port/path(协议名称://主机地址:端口/特定服务的路径),其中path = folder/folder/file。(这几个字段存在线性依赖关系,前面的字段不存在,则后面的字段配置了也会被忽略。)
    如常见的content://表示来自系统ContentProvider中的内容;file://表示来自本机文件系统的文件;http://host:port/path 表示要处理的数据来自于基于http协议网络主机上;用户也可以指定适合自己应用格式的特定的Uri格式,如果是自定义的就不具有通用性了。

    下面说几个Android应用中常见的几个Scheme和用法:

    • ftp / http / https: 你懂得
      • content: ContentProvider的资源。content://djsh/whjdhs/shja.jpg
      • file: 本机文件。file://dsjj/jajs/hjah.pdf
      • tel: 电话功能。tel:180****6680
      • smsto: 消息功能。smsto:180****6680
      • emailto: 邮件功能。emailto:180****6680
      • 自定义: 网页打开应用。
  • mimeType:Multipurpose Internet Mail Extensions,多目的网络邮件扩展,最初是用来表示邮件的附件的类型的,现在也用来表明附件的类型信息。
    一个MIME类型至少包括两个部分:一个类型(type)和一个子类型(subtype)。此外,它还可能包括一个或多个可选参数(optional parameter)。
    比如,HTML文件的互联网媒体类型可能是text/html; charset = UTF-8
    在这个例子中,文件类型为text,子类型为html,而charset是一个可选参数,其值为UTF-8。
    mimeType的常见类型: 这里有对mimeType更加详尽的介绍

    • 超文本标记语言文本 .html text/html
    • 普通文本 .txt text/plain
    • RTF文本 .rtf application/rtf
    • GIF图形 .gif image/gif
    • JPEG图形 .ipeg,.jpg image/jpeg
    • au声音文件 .au audio/basic
    • MIDI音乐文件 mid,.midi audio/midi,audio/x-midi
    • RealAudio音乐文件 .ra, .ram audio/x-pn-realaudio
    • MPEG文件 .mpg,.mpeg video/mpeg
    • AVI文件 .avi video/x-msvideo
    • GZIP文件 .gz application/x-gzip
    • TAR文件 .tar application/x-tar

    mimeType的类型和子类型也可以用*来表示:image/*、video/*等

Category解析

类别,声明所属的类别.一个包含应处理 Intent 组件类型的类别信息的字符串。 您可以将任意数量的类别描述放入一个 Intent 中,但大多数 Intent 均不需要类别。
下面是一些标准的Category:(很多我都不知道啊干嘛的)

ComponentName

组件,包含了指定组件的包名和类名,当我们需要显式地指明处理Intent的组件时指定 ComponentName 的值。
所有的service的启动都应该使用显式意图
如果不指定组件,则由系统根据Intent中的其他信息解析出适合的组件,如果满足条件的组件有多个,则由用户指明使用哪一个组件(如果用户之前没有指定过默认打使用的组件)。

Extras

Intent所携带的额外的数据,如页面跳转的时候,我们可能经常需要传递一些信息到下一个页面去,或者从当前页面返回数据给上一个页面。系统也提供了一些常用的Extra的Key值,比如:

Flag

在 Intent 类中定义的、充当 Intent 元数据的标志。 标志可以指示 Android 系统如何启动 Activity(例如,Activity 应属于哪个任务栈),以及启动之后如何处理。
关于常用Flag的解析,看看任玉刚的这篇博客。
注意:如果是从BroadcastReceiver启动一个新的Activity,或者是从Service往一个Activity跳转时,不要忘记添加Intent的Flag为FLAG_ACTIVITY_NEW_TASK。

显式意图和隐式意图

显式和隐式意图可以根据 Intent 中是否指定了要启动的组件(mComponent 是否指定),指定了特定组件的就是显式意图否则就是隐式意图。

显式意图

按名称(完全限定类名)指定要启动的组件。 通常,您会在自己的应用中使用显式 Intent 来启动组件,这是因为您知道要启动的 Activity 或服务的类名。例如,启动新 Activity 以响应用户操作,或者启动服务以在后台下载文件。
如果 Intent 中 mComponent 不为空,即开发者使用setComponent或者setClass或者setClassName等显式指定处理意图的组件,此时 Intent 中设置的 action、category、data 等不影响组件的选择。适用条件是开发者准确知道可以处理该意图的对象的确切的位置(包名和类名),如果调用对象在应用内可以直接指定 xxxx.class ,如果调用其他应用则需要指定包名以及类名的确切路径。

//显式意图(通过设置 ComponentName 参数指定完成意图的组件)
//设置Component参数一共有三种方式
intent.setClass(this,MainActivity.class);
intent.setClassName(this,"com.nullpointer.stud.MainActivity.class");
intent.setClassName("com.nullpointer.study","com.nullpointer.study.MainActivity");
//其实质都是通过包名和类名构造了一个ComponentName
//打开当前APP内组件可以不指定包名而通过context指定,但是实质还是使用包名
//打开其他应用的组件需要指定完整包名和全限定类名

隐式意图

不会指定特定的组件,而是声明要执行的常规操作,从而允许其他应用中的组件来处理它。 例如,如需在地图上向用户显示位置,则可以使用隐式 Intent,请求另一具有此功能的应用在地图上显示指定的位置。
创建隐式 Intent 时,Android 系统通过将 Intent 的内容与在设备上其他应用的清单文件中声明的 IntentFilter 进行比较,从而找到要启动的相应组件。 如果 Intent 与 IntentFilter 匹配,则系统将启动该组件,并向其传递 Intent 对象。 如果多个 Intent 过滤器兼容,则系统会显示一个对话框,支持用户选取要使用的应用。
隐式意图则是通过设置 Action,Category,Data等之后交给系统( Intent 中的 action 一般都需要指定,Category 可以不设置,如果不设置则默认为只有一个 CATEGORY_DEFAULT ),由系统以及用户选择处理该意图的组件,如果 Activity 希望被隐式意图启动,则必须包含 android.intent.category.DEFAULT。

//通过setAction指定操作的类型,通过setData指定操作的数据,
//通过设置Category限定类别
//通过设置setType指定操作的对象的类型

//Intent.ACTION_DIAL tel:180****6680用于打开拨号界面
//下面的示例就指定了一个打开拨号界面的意图,并且指定了拨号界面的数据是朕的手机号码
intent.setAction(Intent.ACTION_DIAL);
intent.setData(Uri.parse("tel:180****6680"));

//下面的示例就打开了指定的网页
intent.setAction(Intent.ACTION_VIEW);
intent.setData(Uri.parse("http://www.google.com"));

//?下面的示例就打开了搜索结果页面
intent.setAction(Intent.ACTION_WEB_SEARCH);
intent.putExtra(SearchManager.QUERY,"Android");

//需要注意的是 setData和setType互斥,如果需要同时设置 请使用setDataAndType();

public @NonNull Intent setData(@Nullable Uri data)
mData = data;
mType = null;
return this;
}
public @NonNull Intent setType(@Nullable String type) {
mData = null;
mType = type;
return this;
}

Android 提供了很多标准Intent的使用范例,也预置了很多标准Action,Category,Extra的字段等,下面列举一下常用的。

Android 提供了很多标准Intent的使用范例,也预置了很多标准Action

谷歌在线文档

一个不错的中文示例

有些东西没必要去死记硬背,需要的时候去翻文档就好了

IntentFilter 及其 匹配规则

Intent 过滤器是应用清单文件中的一个表达式,它指定该组件要接收的 Intent 类型。 例如,通过为 Activity 声明 Intent 过滤器,您可以使其他应用能够直接使用某一特定类型的 Intent 启动 Activity。同样,如果您没有为 Activity 声明任何 Intent 过滤器,则 Activity 只能通过显式 Intent 启动。

就像前面讲到的,我们可以通过设置 action、category、data参数来让系统帮我们选择进行此操作的组件,或者应用。 Action 指定了将要操作的行为,是打开一个网页还是去打开一个拨号页面,或者是发短信、发邮件等等等等。 Data 就指定了要操作的数据。

我们使用了系统提供的 Action 可以方便地调用系统的一些服务。如果我们的应用需要被别的应用调用呢?这个时候我们可以设置自己应用 Activity 或者 Service 或者 BrocastReceiver 的 interFilter 来告诉系统我们的组件可以处理哪些数据。相信下面的代码大家一定不会陌生:

<!--这是应用的启动页,设置action=main和category=launcher表示这是应用的主屏,打开应用时默认打开的页面-->
<activity android:name=".MainActivity"
    android:label="launcher上显示的名字"
    android:launchMode="singleTop">
    <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
</activity>

下面介绍一下Action,Data,Category的含义和作用,然后给出几个常用的值。

Intent的匹配规则

根据Intent中的配置找到满足条件的IntentFilter,进而找到对应的组件。此处的Intent全部指的是隐式Intent,因为不管显式Intent中action,category,data配置的是什么,Intent都将会传递给显式指定的组件。

Intent的整体匹配规则是:

  • Intent和组件匹配通过的条件:每个组件都可以包含若干个IntentFilter,只要有一个IntentFilter匹配通过,则该组件与该Intent匹配成功。
  • IntentFilter与Intent匹配通过的条件:action,category,data全部匹配通过

提前说一下数学中子集的概念:如果集合A的任意一个元素都是集合B的元素,那么集合A称为集合B的子集。空集合是所有集合的子集。

action的匹配规则:(Intent中的Action是IntentFilter中Action的子集。)

一个IntentFilter可以包含0-n个Action,一个Intent只能包含一个Action。

  • 如果Action字段没有指定,则data里的mimeType字段必须指定。这个是在源码里找到的答案,我之前在测试的时候,想尝试看看如果不指定Action会怎样,后来去源码里找到了答案。
  • Intent中设置的action被包含在IntentFilte所配置的action中,则匹配成功。
  • 另外,如果过滤器没有配置Action,则所有的隐式Intent均无法匹配成功;相反地,如果Intent没有设置Action,则所有配置了Action的IntentFilter均可以与之匹配。
Category的匹配规则:(Intent中的Category是IntentFilter中Category的子集)

一个Intent可以设置多个Category,一个IntentFilter也可以包含0-n个Category。
另外,所有的隐式Intent都包含一个CATEGORY_DEFAULT的Category。

  • Intent中设置的Category全部被包含在IntentFilter中配置的Category中则匹配成功。
  • 另外,Android系统会将CATEGORY_DEFAULT类别传递给startActivity(intent)和startActivityForResult(intent)中的intent,所以只有至少配置了CATEGORY_DEFAULT类别的IntentFilter可以与之匹配;相反地,如果过滤器没有配置Category,则所有的隐式Intent均无法与之匹配成功。
Data的匹配规则:

一个 IntentFilter 可以配置0-n个data,一个Intent只能包含一个data.
前面已经说过了data分为两部分: Uri 和 mimeType ,因此 data 的匹配也要分成两部分进行匹配。

Uri的匹配规则:

根据前面所讲到的知道Uri也分为四个部分:scheme、host、port、path。则Uri的匹配规则如下

  • 如果 IntentFilter 中值配置了 scheme ,则 Intent 中的 scheme 与 IntentFilter 中的 scheme 一致即可, 如果 Intent 中 scheme 之后配置有后面的字段,不影响匹配结果。
  • 如果 IntentFilter 中值配置了 scheme 和 host ,则Intent中的 scheme 和 host 必须分别与 IntentFilter 中的 scheme 和 host 一致才能匹配成功。如果 Intent 中 host 之后配置有后面的字段,不影响匹配结果。
  • 如果 IntentFilter 中值配置了 scheme 、 host 、port ,则Intent中的 scheme 、 host 、port
    必须分别与 IntentFilter 中的 scheme 、 host 、port一致才能匹配。如果 Intent 中 port 之后配置有后面的字段,不影响匹配结果。
  • 如果 IntentFilter 中值配置了 scheme 、 host 、port 、path ,则Intent中的 scheme 、 host 、port、path
    必须分别与 IntentFilter 中的 scheme 、 host 、port、path 一致才能匹配。IntentFilter 中path中可以包含通配符,只要 IntentFilter 中 path 与 Intent 中的 path Match即可通过匹配。
  • Uri中path的匹配path、pathPrefi、pathPattern都可以用来进行path的配置,下面说一下他们之间的区别
  • path 用来匹配完整的路径,如:”https://developer.android.com/reference/android/content/Intent.html” ,这里将 path 设置为 “/reference/android/content/Intent.html” 才能够进行匹配;
  • pathPrefix 用来匹配路径的开头部分,拿上面的 Uri 来说,这里将 pathPrefix 设置为 “/reference” 或者 “/android/content” 就能进行匹配了;
  • pathPattern 用表达式来匹配整个路径,本例中可以用 “.*\.html” 匹配所有以.html 结尾的路径(注意字符的反义)。这里需要说下两种匹配符号。

匹配符号:

  • “*” 用来匹配0次或更多,如:”a*” 可以匹配”“、”a”、”aa”.
  • “.” 用来匹配任意单个字符,如:”.” 可以匹配”a”、”b”,”c”.

因此 “.*” 就是用来匹配任意字符0次或更多,如:”.*.html” 可以匹配 “abc/def/ghi/jkl.html”、”ccbh.tml”;”/reference/.*.html”表示以 “/reference” 开始 以”.html”结尾的路径。(“.html” 表示 html 前面有任意一个字符,”.html” 表示以 .html 结尾)

mimeType的匹配规则:
  • 父类型是*则子类型只能是*,可以通配所有的mimeType。如*/*可以匹配abc/def也可以匹配acb/fed。
  • 父类型为常规值,子类型是*,可以统配父类型下的所有子类型。如image/*既可以匹配image/jpg也可以匹配image/png。
  • 父类型和子类型均为常规值,则需要两个都同时匹配才可以匹配成功。如text/html只能匹配text/html
Uri和MimeType结合时的匹配规则(从Intent的角度出发)
  1. 如果Intent没有配置Uri和mimeType,则只能匹配到也未配置Uri和mimeType的IntentFilter。
  2. 如果Intent包含Uri但是不包含mimeType(没有显式指定,也无法根据Uri推断出来),则只能匹配到Uri匹配且也未配置mimeType的IntentFilter。换言之,如果IntentFilter配置了mimeType,则无法匹配成功。
  3. 如果Intent包含mimeType但是不包含Uri,则只能匹配到mimeType匹配成功,且没有配置Uri的IntentFilter.换言之,如果IntentFilter配置了Uri,则无法匹配成功。
  4. 如果Intent同时包含mimeType和Uri,匹配成功的IntentFilter必须满足的首要条件是配置了的mimeType与Intent中设置的相互匹配。其次匹配成功的第二个条件是:
  • Intent的Uri为content或者file类型:IntentFilter可以没有配置Uri(如果IntentFilter配置了mimeType,没有配置Uri,系统假定组件支持content:或者file:类型的Uri),或者也配置了与Intent中Uri匹配的Uri.
  • Intent的Uri不为content或者file类型:IntentFilter也配置了与Intent中Uri匹配的Uri.

1、2和4可能还算用的多的,3并不会怎么用。3是不包含Uri但是指定了mimeType,资源都没有,资源的类型也就毫无意义了,所以不是很常用。

Uri和MimeType结合时的匹配规则(从IntentFilter的角度出发)
  1. 如果IntentFilter没有配置Uri和mimeType,则只能匹配到没有配置Uri和mimeType的Intent。
  2. 如果IntentFilter配置了Uri没有配置mimeType,则只能匹配到同样Uri且未配置mimeType的Intent。
  3. 如果IntentFilter配置了mimeType没有配置Uri,则系统假定组件支持content:或者file:类型的Uri,所以只能匹配到配置了相同mimeType(没有显示指定但是可以推断出的也可以)且Uri类型为content:或者file:的Intent。
  4. 如果IntentFilter同时配置了Uri和mimeType,则可以匹配到配置了匹配的Uri和匹配的mimeType的Intent。

其实上面的规则很好理解:IntentFilter是用来处理数据的,所以他要处理的数据的范围必须要大于Intent中设置的数据的范围(范围同时包含Uri类型和mimeType类型)。如果遵守的协议都不一样,肯定没办法处理啊,如果能处理的mimeType也无法匹配,那就自然也处理不了了。
有一个规律就是,Intent中未配置的项默认范围最大,IntentFilter未配置的项默认范围最小。比如:

  • 如果Intent中不包含Uri则默认Intent配置的Uri是最大的范围,所以配置了Uri的IntentFilter的Uri范围自然变小,不是包含关系,所以没法处理;mimeType也是同样的。
  • 如果IntentFilter中不包含Uri,系统给了content和file的默认值,不包含mimeType时,所有配置了mimeType的Intent均无法与之匹配成功。

根据上面的介绍的匹配规则看一下下面的示例:

<!--假设现在有一个Activity在清单文件中的设置如下:-->
    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">

        <!--该Activity将会出现在Launcher上,并且Launcher上的标题是“启动页面”-->
        <activity android:name=".MainActivity"
                android:label="启动页面">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

        <!--因为没有任何设置Action和data,所以无法通过隐式Intent启动-->
        <activity android:name=".NoActionActivity"
            android:label="NoActionActivity">
            <intent-filter>
                <category android:name="com.nullpointer.intentdemo.DEMO_CATEGORY" /
                <category android:name="android.intent.category.DEFAULT"/>
            </intent-filter>
        </activity>

        <!--因为没有设置任何Category,所以无法通过隐式Intent启动-->
        <activity android:name=".NoCategoryActivity"
            android:label="NoCategoryActivity">
            <intent-filter>
                <action android:name="com.nullpointer.intentdemo.DEMO_ACTION" />
            </intent-filter>
        </activity>

        <!--因为没有设置默认Category,所以无法通过隐式Intent启动-->
        <activity android:name=".NoDefaultCategoryActivity"
            android:label="NoDefaultCategoryActivity">
            <intent-filter>
                <action android:name="com.nullpointer.intentdemo.DEMO_ACTION" />
                <category android:name="com.nullpointer.intentdemo.DEMO_CATEGORY" />
            </intent-filter>
        </activity>

        <!--匹配成功的隐式Intent必须满足满足以下条件-->
        <!--1. Action属性只能是 com.nullpointer.intentdemo.DEMO_ACTION -->
        <!--2. Category属性可以不配置,否则只能添加一个com.nullpointer.intentdemo.DEMO_CATEGORY-->
        <!--3. Uri和mimeType均没有进行配置-->
        <activity android:name=".NoDataActivity"
            android:label="NoDataActivity">
            <intent-filter>
                <action android:name="com.nullpointer.intentdemo.DEMO_ACTION" />
                <category android:name="com.nullpointer.intentdemo.DEMO_CATEGORY" />
                <category android:name="android.intent.category.DEFAULT"/>
            </intent-filter>
        </activity>

        <!--匹配成功的隐式Intent必须满足满足以下条件-->
        <!--1. Action属性只能是 com.nullpointer.intentdemo.DEMO_ACTION 或者 android:name="android.intent.action.VIEW"-->
        <!--2. Category属性可以不配置,否则只能添加一个com.nullpointer.intentdemo.DEMO_CATEGORY-->
        <!--3. Uri进行了配置,并且协议用的"demo",剩下的字段(host、port、path)是否配置,配置成什么都无所谓,mimeType未进行配置-->
        <activity android:name=".NoMimeTypeActivity"
            android:label="NoMimeTypeActivity">
            <intent-filter>
                <action android:name="android.intent.action.VIEW"/>
                <action android:name="com.nullpointer.intentdemo.DEMO_ACTION" />
                <category android:name="com.nullpointer.intentdemo.DEMO_CATEGORY" />
                <category android:name="android.intent.category.DEFAULT"/>
                <data android:scheme="demo" />
            </intent-filter>
        </activity>

        <!--匹配成功的隐式Intent必须满足满足以下条件-->
        <!--1. Action属性如果不配置,则mimeType必须配置为“demo/mime”,或者只能是  com.nullpointer.intentdemo.DEMO_ACTION -->
        <!--2. Category属性可以不配置,或者添加com.nullpointer.intentdemo.DEMO_CATEGORY1/2/3中的一个两个或者三个全部添加-->
        <!--3. mimeType进行配置为“demo/mime”或者“*/*”,或者未进行配置-->
        <activity android:name=".NoUriActivity"
            android:label="NoUriActivity">
            <intent-filter>
                <action android:name="com.nullpointer.intentdemo.DEMO_ACTION" />
                <category android:name="com.nullpointer.intentdemo.DEMO_CATEGORY1" />
                <category android:name="com.nullpointer.intentdemo.DEMO_CATEGORY2" />
                <category android:name="com.nullpointer.intentdemo.DEMO_CATEGORY3" />
                <category android:name="android.intent.category.DEFAULT"/>
                <data android:mimeType="demo/mime"/>
            </intent-filter>
        </activity>

        <!--匹配成功的隐式Intent必须满足满足以下条件-->
        <!--1. Action属性如果不配置,则mimeType必须配置为“demo/mime”,或者只能是  android.intent.action.VIEW -->
        <!--2. Category属性可以不配置,或者添加com.nullpointer.intentdemo.DEMO_CATEGORY-->
        <!--3. mimeType进行配置为“demo/mime”或者“*/*”,Uri的scheme定义为“demo”,-->
        <activity android:name=".HaveBothActivity"
            android:label="HaveBothActivity">
            <intent-filter>
                <action android:name="android.intent.action.VIEW"/>
                <category android:name="com.nullpointer.intentdemo.DEMO_CATEGORY" />
                <category android:name="android.intent.category.DEFAULT"/>
                <data android:scheme="demo" android:host="test" android:port="1234" android:path="path" android:mimeType="demo/mime"/>
            </intent-filter>
        </activity>
    </application>

这个问题可以说是很大的问题了。简要说一下,详细的就太多内容了。
参考:
欧阳辰的专栏-移动DeepLink的前世今生
google training-Deep Linking and Android App Links

网页打开应用

常见的应用大都会为他们的应用提供App和网页两种访问途径,但是显而易见的是APP可以提供更好的用户体验,因此从网页进入我们的App也就成为了一种需求。目前从网页进入App的途径就是通过设置Activity的IntentFilter。
如下面的这个Activity就可以允许网页打开自己。

<activity 
    android:name=".UserInfoActivity"
    android:label="用户信息">
        <intent-filter>
            <action android:name="android.intent.action.VIEW"/>
            <category android:name="android.intent.category.BROWSABLE"/>
            <category android:name="android.intent.category.DEFAULT"/>
            <data android:scheme="nullpointer" host="com.nullpointer.demo" path="/userInfo"/>
         </intent-filter>
</activity>

上面这个页面是一个用于展示用户信息的页面,我们配置了一个用于网页打开的过滤器(当然也可以再配置一些用于其他用途的过滤器),我们在这个过滤器中配置了 action,category 以赋予我们的应用可以被网页打开的能力,设置data的值来确保我们的当前只响应我们感兴趣的Uri.

ACTION_VIEW 用于展示数据,总是必须的。
CATEGORY_BROWSABLE 允许我们的应用可以被浏览器打开,因此也是必须的。
CATEGORY_DEFAULT 允许我们的应用允许被隐式意图打开,因而也是必须的。
通过设置Data中scheme、host、path或者path的变种,允许特定的链接才能打开我们的当前页面。

将下面的网页在浏览器中打开,然后点击页面上的“打开我的应用”链接,即可打开我们的App:

<!DOCTYPE html>  
<html>  
    <body>
        <h1>Test Scheme</h1> 
        <!—自动加载隐藏页面跳转—>
        <!-- <iframe src="myscheme://www.orangecpp.com:80/mypath?key=mykey" style="display:none"></iframe> -->
        <!—手动点击跳转—>
        <a href="nullpointer://com.nullpointer.demo/userInfo?userId=001">打开我的应用</a>
    </body>  
</html>

然后我们在App中这样获取应用的参数:
在这里,我们是直达需要的页面,有时候也可以配置一个统一的入口,然后根据参数来确定打开哪个页面。

//因为可以打开我们的这个页面,所以前面的host,path都不要再提了
Intent intent = getIntent();
if (TextUtils.equals("nullpointer",intent.getScheme())){
    Uri uri = intent.getData();
    String userId = uri.getQueryParameter("userId");
    //获取了userId,就爱干啥干啥吧
    Toast.makeText(this,"获取的用户Id是"+userId,Toast.LENGTH_SHORT).show();
}

建立深度链接

在上面的实例中,我们只是确保了我们的app中的页面可以被浏览器打开,然后通过携带的参数进行相应的展示,这并不符合谷歌对深度链接的定义。
深度链接的一个显著特征是:在用户通过浏览器得到的搜索结果中,当点击某一条来自与当前App配套的网页的结果的时候,浏览器可以直接打开我们的应用(甚至不需要用户选择要打开的App),而不是先进入网页,然后再打开我们的App。

<!--通过站点地图添加深度链接-->
<?xml version="1.0" encoding="UTF-8" ?>
<urlset
    xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"
    xmlns:xhtml="http://www.w3.org/1999/xhtml">
    <url>
        <loc>example://gizmos</loc>
            <xhtml:link
                rel="alternate"
                href="android-app://com.example.android/example/gizmos" />
    </url>
    ...
</urlset>

<!--在特定的页面上添加深度链接-->
<html>
<head>
    <link rel="alternate"
          href="android-app://com.example.android/example/gizmos" />
    ...
</head>
<body> ... </body>

好了,关于Intent的基本知识就先到这里为止了。

Android 监听apk安装替换卸载广播的实现代码 首先是要获取应用的安装状态,通过广播的形式以下是和应用程序相关的Broadcast ActionACTION_PACKAGE_ADDED 一个新应用包已经安装在设备上,数据包括包名(最新安装的包程序不能接收到这个广播)ACTION_PACKAGE_REPLACED 一个新版本的应用安装到设备,替换之前已经存在的版本ACTION_PACKAGE_CHANGED 一个已存在的应用程序包已经改变,包括包名ACTION_PACKAGE_REMOVED 一个已存在的应用程序包已经从设备上移除,包括包名(正在被安装的包程序不能接收到这个广播)ACTION_PACKAGE_RESTARTED 用户重新开始一 立即下载

相关推荐

别再纠结高边低边了!用TI BQ76952设计两轮车BMS,手把手教你选对架构(附电路图)

本文深度解析基于TI BQ76952芯片的电动两轮车BMS设计策略,涵盖高边/低边驱动选择、四种基础架构的电流路径分析及选型决策矩阵。通过实战案例分享,帮助工程师优化BMS架构,提升系统可靠性和成本效益,特别适合电摩和共享单车应用场景。

weixin_42665255的博客 514

Android侦听应用(Package)变化的方法(1)侦听广播

应用的状态变化,包括安装、卸载、更新,是android系统上重要的事件。如何侦听到?有两种方法,一是通过侦听广播,一是实现PackageMonitor。 侦听广播 当Package状态发生变化时,系统会广播如下一些Action的Intent: 应用安装: public static final String ACTION_PACKAGE_ADDED = "android

@甘道夫@的专栏 1万+

Abaqus中使用Python提取裂缝数据并用matplotlib库绘图

ABAQUS后处理PYTHON二次开发代码:提取裂缝数据并用matplotlib库绘图

qq_42568527的博客 3470

android 安装apk以及安装失败的监听

监听Apk卸载、改变、及安装 在android监听这几种状态,其实是非常简单的,就是利用广播来进行监听 以下是和应用程序相关的Broadcast Action ACTION_PACKAGE_ADDED 一个新应用包已经安装在设备上,数据包括包名(最新安装的包程序不能接收到这个广播) ACTION_PACKAGE_REPLACED 一个新版本的应用安装到设备,替换之前已经存在的版本 ACTION_PACKAGE_CHANGED 一个已存在的应用程序包已经改变,包括包名 ACTION_PACKAGE_REMO

xianrenli38的博客 4590

2022年电赛E题声源定位跟踪系统

电赛声源定位

qq_53357019的博客 2万+

IgH EtherCAT 从入门到精通:第 2 章 环境搭建与编译安装

环境搭建与编译安装指南 本章详细介绍了搭建IgH EtherCAT Master开发环境的完整流程。内容包括: 硬件要求:支持多种Intel和Realtek网卡的原生驱动,以及通用网卡的generic驱动选项 软件依赖:列出Linux系统下所需的工具链和开发包 源码获取:通过Git克隆官方仓库并切换稳定版本的方法 配置选项:详细解析bootstrap脚本和configure的核心参数,包括路径设置、功能开关和实时框架选项 编译流程:从生成构建系统到最终编译安装的完整步骤 通过本章指导,读者可以完成一个可运行

从事嵌入式linux android驱动开发,拥有全栈能力 479

android中的Package安装、卸载、更新替换流程

android系统在安装,删除,替换,清除数据等与应用相关的动作时,会发出对应的Broadcast,上层的应用通过注册相应的广播事件来做相应的处理。1,ACTION_PACKAGE_ADDED----------当有新的包安装成功的时候,系统会发出此广播。2,ACTION_PACKAGE_REMOVED-----当有包被卸载的时候,系统会发出此广播。3,ACTION_PACKAGE_REPLACED----当有包被更新的时候,系统会发出此广播。上面两种广播的用法,很多朋友也已经很熟悉,通过。

yzwfeng的专栏 2880

微信小程序 - 最新详细实现调起手机摄像头拍摄身份证人像面和国徽面取景框功能,在拍照相机上增加身份证证件照的轮廓或自定义文字,支持替换扫描拍摄辅助线图片及文本,小程序实现拍照身份证时带取景轮廓框拍摄!

微信小程序,身份证,证件照,人像,证件照提示框模板,vue身份证拍照框,摄像机相机里有引导内容,取景框拍摄,微信小程序实现拍照界面自定义实现,自拍人相框拍摄,取景框,户口簿取景框,画布指定区域生成图片,微信小程序身份证正反面拍照如何加入辅助图片引导照片,身份证取景框拍摄,服务器,上传,正反面,调起手机摄像头:拍摄身份证的正反面,自定义身份证取景框,在相机上绘制“身份证轮廓“与提示文字,拍摄身份证时出现人像框怎么实现,在相机上增加图片和文字,微信小程序怎么给调起的相机加入自定义图片,小程序实现给相机上面

🏆 前端领域优质创作者 1万+

Android 监控程序安装和删除的实现

通过阅读Android SDK里关于intent.action这部分里面的描述,我们可以找到一些与package相关的系统广播 android.intent.action.PACKAGE_ADDED android.intent.action.PACKAGE_CHANGED android.intent.action.PACKAGE_DATA_CLEARED

5373

170、电机控制中的温升测试

本文以一次IGBT炸管事故为切入点,深入剖析电机控制中温升测试的实质:不仅是温度测量,更是对铜损、铁损、散热效率等热管理问题的系统验证。作者强调测试前热电偶布置、环境记录、预运行的重要性,提出实时监控电流谐波、绕组电阻、散热梯度等关键参数,并通过损耗分离与冷却系统实测,揭示真实热源。结合温升曲线异常分析与经验建议,强调留余量、仿真结合实测、关注瞬态工况等实践要点,警示温升测试是保障可靠性与安全性的核心环节。

2401_88858637的博客 48

2026 年第十六届MathorCup数学应用挑战赛题目C题中老年人群高血脂症的风险预警及干预方案优化 2026妈妈杯 详细思路、代码、模型

2026 年第十六届MathorCup数学应用挑战赛题目 C题中老年人群高血脂症的风险预警及干预方案优化 人口老龄化进程的持续加快,使得40岁及以上中老年人群成为 慢性病防控的核心群体,其中高血脂症的发病率呈逐年攀升态势, 已成为诱发冠心病、脑梗死等心脑血管疾病的重要危险因素,严重 威胁中老年群体的心血管健康与生活质量,也加重了基层医疗的慢 病管理负担。从中医体质学视角来看,体质禀赋与偏颇是疾病发生 发展的内在根基,其中痰湿体质为中老年高血脂症的高发体质类型, 该体质人群存在痰湿内蕴、脾胃运化失常、水湿代谢

YOLO 755

android Intent机制详解

什么是Intent Intent是一种运行时绑定(run-time binding)机制,它能在程序运行过程中连接两个不同的组件。通过Intent,你的程序可以向Android表达某种请求或者意愿,Android会根据意愿的内容选择适当的组件来完成请求。比如,有一个Activity希望打开网页浏览器查看某一网页的内容,那么这个Activity只需要发出WEB_SEARCH_ACTION给An...

mmdev 486

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

14天学会安卓开发(第二天)Android程序设计基础activity和intent

14天学会安卓开发   作者:神秘的N (英文名  corder_raine) 联系方式:369428455(反馈) 交流群:284552167(示例,原文档下载) 版权为作者所有,如有转载请注明出处 目录 第二天Android程序设计基础... 31 2.1 深入了解安卓... 31 2.1.1 工程结构解析... 32

corder_raine的专栏 2426

visio安装包

Microsoft Office Visio 是一款专业的制图软件。利用经过更新的形状、协作工具和数据链接图表,创建专业级图表以简化复杂的信息。

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

Android基础学习之Intent

<br /> <br />Android用Intent这个特殊类实现Activity与Activity之间的切换。Intent类用于描述应用的功能。在Intent的描述结构中,有两个最重要的部分:动作和动作对应的数据。<br />  Intent作用的表现形式为:<br />      1、通过Context.startActivity() orActivity.startActivityForResult() 启动一个Activity;<br />      2、通过 Context.startServi

chenlei1889的专栏 1311

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

Android-基础-intent

mark

Just______的博客 326

Android基础——Intent

IntentIntent是什么?显式Intent隐式Intent Intent是什么? Intent用于Android程序中各组件(Activity、BroadcastReceive、Service)的交互,并且可以在组件之间传递数据,分为显式Intent和隐式Intent。 显式Intent 通过Intent(Context packageContext, Class<?> cls)构造函数创建Intent实例,第一个参数为当前Context,第二个参数为要启动的目标类。如当需要启动Other

松仔Log的博客 3340

Android常用Intent 和URI——基础总结

最近发现,闲下来的时候静心写写博客也是一件挺开心的事情,总结一下以往的知识点。 之所以还停留在初级阶段,很大的原因是没有做过总结,梳理一下零碎的知识。。。 学习终归是个水滴石穿的过程,再聪明的人都抵不过一点一滴的积累,更何况本来就是个聪明人。加油! Internet表明了我们的各种意图,开发app的过程中有各种Internet(打电话、发短信、浏览网页、、),让我们由浅入深。。。。 p

树先生 4472

Android基础 : 第二部分 - Intent接收器

Android基础 : 第二部分 - Intent接收器 http://www.fulema.com/viewthread.php?tid=4&extra=page%3D1 我们来了解一些关于Intent接收器的相关知识。 Android的Intent接收器是Android事件处理机制中的一部分,它可以进行动作的广播,因此,我们可以用它来作为事件处理器。 创建Intent接收器

菲利克斯猫(Felix.mao)的IT技术专栏 2331

安卓基础之Intent的用法

采用startActivityForRequest()方法而不是startActivity()隐式意图用于开启其他应用的Activity(主要是系统应用),相比显示意图安全性较差.假如在TestActivity.class页面中点击按钮把选中号码返回,显示意图用于开启自己应用内的Activity.显示意图:通过指定具体的activity实现。重写方法onActivityResult()隐式意图:通过指定一组数据或者动作实现。在以上的例子中,数据由。

m0_72345017的博客 1161

Android开发基础之Intent

★Intent的对象包含的一组信息 首先我们要先了解一下下面这些对象的含义是什么? Component name:要启动的组件或哪个activity的名字    Action:指定要做的动作 Data:传送的数据                                                             Extras:另外的键值对 当然还有其他的对象,但是在

feili12138的博客 451

Android Intent基础

Intent 是 Android 一个常用的用于组件间互相通信的信息对象,它不仅可以指明当前组件想要执行的动作,还可以在不同组件之间进行数据传递。 基本用例主要包括以下三个: 启动 Activity Activity 表示应用中的一个屏幕。通过将 Intent 传递给 startActivity(),您可以启动新的 Activity 实例。Intent 用于描述要启动的 Activity,并携...

秋殇阁 387

Android基础之Intent 和 Intent 过滤器

长日尽处,我站在你的面前,你将看到我的疤痕,知道我曾经受伤,也曾经痊愈。

Wtoria的博客 4660

Android基础之Intent

一、生活缩影 今天早上又没有早起床,哎,怪只能怪自己的意志力不够,明天一定要早起,今天看到了一句话------不想输,就别懒。 今晚上心情不是很高兴,至于原因就不说了,总而言之,还是怪自己高估了自己在别人心中的地位,而自己跟一个二逼似的老是将自己有感觉的人放在心中 很高的地位,我觉得自己心情的不好就是源于这个吧,以后真的就只对自己的父母,兄弟好以及那几个真正对我好的女生,绝对不会在与自己未来

耀相惜 545

安卓基础(Intent)

【代码】安卓基础(Intent)

hongsegeming的博客 531
上一篇: Activity基础知识
下一篇: Android消息机制详解
ApiPlayer
博客等级 码龄12年 34粉丝 17原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值