2. Intent与组件
Intent促进组件之间的交互,这对于开发者来说非常重要,同时它也可以作为消息的载体来引导组件做出相应的行为。也就是说,Intent可以携带数据,传递给Activity/Service/BroadcastReceiver。 开始活动。 Activity可以简单理解为手机屏幕上的一个页面。您可以通过将Intent 传递到startActivity 方法来启动一个Activity 实例(即一个页面)。同时,Intent还可以携带数据,传递给新的Activity。如果想获取新Activity的执行结果,可以通过onActivityResult()方法启动该Activity。启动服务。 Service是后台执行操作组件,不呈现交互屏幕。您可以通过将Intent 传递到startService() 方法来启动服务来启动服务。提供广播。广播是任何应用程序都可以接收的消息。通过将Intent 传递给sendBroadcast()、sendOrderedBroadcast() 或sendStickyBroadcast() 方法,可以将广播传送到接收者。3. Intent类型
在Android中,Intent分为显式和隐式两种。 Explicit Intent可以通过类名找到对应的组件。显式意图用于启动应用程序中的组件,通常是因为我们知道组件的名称(活动或服务)。在下面的代码中,我们知道了具体Activity的名称。启动一个新的Activity,下面是使用的显示Intent。 Intent意图=new Intent(context, XXActivity.class); 启动活动(意图);隐式Intent没有指定具体的组件,但它声明了要执行的操作以匹配相应的组件。 Android中调用系统拨号页面准备通话最简单的操作就是隐式Intent。 意图intent=new Intent(Intent.ACTION_DIAL); Uri数据=Uri.parse("tel:" + "135xxxxxxxx");
意图.setData(数据);
启动活动(意图);当使用display Intent启动Activity或Service时,系统会立即启动Intent对象中指定的组件。
使用隐式Intent时,系统通过比较Intent对象中的IntentFilter与AndroidManifest.xml或代码中组件动态声明的IntentFilter来找到对应的需要启动的组件。如果组件的IntentFilter与Intent中的IntentFilter完全匹配,系统将启动该组件并将Intent传递给它。如果同时匹配多个组件,系统会弹出一个选择框,让用户选择使用哪个应用程序来处理该Intent。例如,有时单击网页链接时,会弹出多个应用程序,让用户选择使用哪个浏览器。当您打开此链接时就会出现这种情况。
IntentFilter通常定义在AndroidManifest.xml文件中,也可以动态设置。它通常用于声明组件想要接受什么样的Intent。例如,如果为某个Activity设置了IntentFilter,则可以使用特定的隐式Intent来启动本应用程序或其他应用程序中的Activity。如果没有为Activity设置IntentFilter,那么只能通过显示Intent来启动它。本次活动。
注意,为了保证系统的稳定性,官方建议使用显式Intent启动Service,并且不要为Service设置IntentFilter,因为如果使用隐式Intent启动Service,我们不知道哪些服务会响应到Intent,而且由于大多数服务是不可见的,我们不知道哪些服务启动了,这是非常危险的。 Android 5.0(API 21)之后,如果使用隐式Intent调用bindService()方法,系统会抛出异常。
4. Intent的属性
Intent作为消息的载体。系统用它来决定启动哪个特定组件,同时传输组件执行所需的信息。 Intent 可以包含的属性包括Component、Action、Data、Category、Extras 和Flags。有关这些属性的更多详细信息可以在此处找到。
组件,要启动的组件的名称。该属性是可选的,但它是显式Intent的一个重要属性。设置该属性后,Intent只能传递给Component定义的组件。隐式意图没有这个属性。系统根据其他信息(例如Action、Data等)确定Intent应该传递给哪个组件。该属性是目标组件的具体名称(完全限定类名),例如com.example.DemoActivity。该属性可以通过setComonentName()、setClass()、setClassName() 或Intent 构造函数设置。 Action,一个字符串,指示要执行的操作。它会影响Intent的其他信息,例如Data和Extras。该属性可以通过setAction() 方法或Intent 构造函数来设置。用户可以自定义该属性或使用系统中已有的Action 值。下面列出了启动Activity 时的一些常见Action 属性。 ACTION_VIEW。当有一些信息需要显示时,可以将Intent的Action设置为该值,并调用startActivity()方法。 ACTION_SEND。当用户有一些信息需要与其他应用程序共享时,可以将Intent的Action设置为该值并调用startActivity。 ()方法ACTION_DIAL,要进行呼叫,可以将Intent的Action设置为这个值,并调用startActivity()方法ACTION_EDIT,要编辑一些文件,可以将Intent的Action设置为这个值,然后调用startActivity() 方法Data,即操作数据的引用URI 或数据MIME 类型的URI。它的值通常与Intent 的Action 相关联。例如,如果将操作值设置为ACTION_EDIT,则数据值必须包含正在编辑的文档的URI。当我们创建Intent时,设置MIME类型非常重要。例如,可以显示图片的Activity 可能无法播放音频。图片和音频的URI非常相似。如果我们设置MIME类型,它可以帮助系统找到最合适的组件来接受Intent。有时,MIME 类型也可以从URI 确定。例如,当Data是包含content:字符串的URI时,你可以清楚地知道要处理的数据存在于设备中,并且由ContentProvider控制。使用setData() 方法设置数据引用的URI,使用setType() 方法设置数据的MIME 类型,使用setDataAndType() 方法同时设置这两个属性。
注意:如果要设置两个属性,请直接使用setDataAndType()方法。不要同时调用setData()和setType()方法,因为这两个方法设置的值会互相覆盖。
公共意图setData(Uri数据){
mData=数据;
mType=null;
返回这个;
}
公共意图setType(字符串类型){
mData=空;
mType=类型;
返回这个;
}类别,该属性是对Intent组件信息处理的补充。它是一个ArraySet类型的容器,因此可以向其中添加任意数量的补充信息。同时,如果Intent不设置该属性,也不会影响组件信息的解析。该属性可以通过addCategory() 方法设置。下面列出了一些常用的类别值。 CATEGORY_BROWSABLE,将Category设置为该值后,当点击网页上的图片或链接时,系统会考虑将该目标Activity包含在可选列表中,供用户选择打开该图片或链接。 CATEGORY_LAUNCHER,应用程序启动的初始Activity,该Activity将被添加到系统启动器中。上面列出的Intent的属性(Component、Action、Data、Category)可以帮助系统确定具体的组件,但是Intent有一些属性不会影响组件的确定。
Extras以键值对的形式存储组件执行过程中所需的附加信息。您可以调用putExtra() 方法来设置该属性。该方法接受两个参数,一个是key,另一个是value。还可以实例化一个存储附加信息的Bundle对象,然后调用putExtras()方法将我们实例化的Bundle添加到Intent中。 Flags,这个属性可以指示系统如何启动一个Activity以及启动后如何处理它。比如该Activity属于哪个任务(参考Activity的四种启动方式)。
5. 显式Intent示例
如上所述,显式Intent是用于启动特定组件(Activity或Service)的Intent。创建显式Intent时,需要设置组件名称(Component)属性,其他属性均为Optional属性。
//fileUrl 是一个URL 字符串,例如"http://www.example.com/image.png"
Intent downloadIntent=new Intent(context, DownloadService.class);
downloadIntent.setData(Uri.parse(fileUrl));
启动服务(下载意图);这里的Intent构造函数传入两个参数,上下文和组件名称(Component)。调用startService()方法后,当前应用程序中将启动DownloadService服务。
显示Intent中设置的组件名称(Component)需要在AndroidManifest.xml中注册,因此一般用于启动当前应用中的组件。
6. 隐式Intent示例
隐式意图比显式意图更复杂。它可以启动当前应用程序内的组件或当前应用程序外的组件。如果当前应用程序无法处理隐式Intent,但其他应用程序中的组件可以,则系统将弹出一个框,允许用户选择哪个应用程序启动该组件。
例如,如果用户有内容想要与其他应用共享,则创建一个Intent,将其Action属性设置为ACTION_SEND,然后将要共享的内容设置为Extras属性,然后调用startActivity()方法,用户可以选择将内容发送到哪个应用程序来共享。
请注意,如果没有应用程序可以处理用户发送的不可见Intent,则调用组件将失败并且应用程序可能会崩溃。调用resolveActivity()方法可以确认是否存在可以处理该Intent的Activity。如果返回值非空,则至少有一个组件可以处理该Intent。调用startActivity()是安全的;如果返回值为空(null),则表示没有任何组件可以处理这个Intent,此时不应该使用这个隐式Intent。
//共享textMessage信息
意图sendIntent=new Intent();
sendIntent.setAction(Intent.ACTION_SEND);
sendIntent.putExtra(Intent.EXTRA_TEXT, textMessage);
sendIntent.setType("文本/纯文本");
//确认是否有组件可以处理这个隐式Intent
if (sendIntent.resolveActivity(getPackageManager()) !=null) {
启动活动(发送意图);
}当调用startActivity()传入隐式Intent时,系统会检查设备中的所有应用程序,以确定哪些应用程序可以处理该隐式Intent(包含startActivity()操作并携带text/plain类型的Intent)。如果只有一个应用程序可以处理这个Intent的话,那么直接调用该应用程序并将Intent传递给它;如果有多个应用程序可以处理这个Intent,那么系统会弹出一个选择框让用户选择调用哪个应用程序。
7. 强制唤起选择框
上面提到,如果多个应用程序可以处理同一个隐式Intent,系统会弹出一个选择框让用户选择调用哪个应用程序,并将该应用程序设置为默认打开方式,从而使选择框以后就不会再出现了。如果用户将来想要使用这个用户来处理这个隐式Intent(例如,当打开网页时,用户通常倾向于使用同一个网页浏览器),这非常方便。
但是,如果用户每次都想使用不同的应用程序来处理这个隐式Intent,则每次都应该弹出选择框。用户可以在选择框中选择诱发的应用程序,但不能设置默认的打开方式。例如,当用户想要根据当前位置将内容共享到不同的应用程序时,每次都需要弹出一个选择框。
用户需要通过Intent.createChooser()创建一个Intent,然后调用startActivity()。
Intent sendIntent=new Intent(Intent.ACTION_SEND);
.
//共享标题
字符串标题=getResources().getString(R.string.chooser_title);
//创建一个调用选择框的Intent
意图选择器=Intent.createChooser(sendIntent, title);
//确认是否有应用程序可以处理这个Intent
if (sendIntent.resolveActivity(getPackageManager()) !=null) {
启动活动(选择器);
8. 接受隐式Intent
要配置您的应用程序可以处理哪些隐式Intent,您需要使用AndroidManifest.xml 文件中的标签为组件设置一个或多个过滤器。每个过滤器根据操作、数据和类别指定它可以处理的意图类型。如果隐式Intent可以匹配用户设置的过滤器之一,则系统可以唤起应用程序的相应组件并将Intent传递给该组件。
组件应该为它可以处理的每个操作都有一个单独的处理程序。例如相册中的Activity可能有两个过滤器,一个过滤器对应浏览照片的操作,另一个过滤器对应编辑照片的操作。当这个Activity启动时,它会根据Intent中携带的信息来决定执行哪个操作。
每个过滤器都使用嵌套在组件标签(例如tag)中的标签在AndroidManifest.xml 中定义。在标签中,用户可以使用以下三个属性中的一个或多个来指定可接受的Intent。
,在此属性中,声明组件可以执行的操作。该值必须是有关操作的字符串,而不是类常量。使用一个或多个数据URI(scheme、host、port、path等)和数据的MIME类型来指定接受的数据类型并声明接受的Intent。对于要接受隐式Intent 的Activity 组件,它必须具有属性为CATEGORY_DEFAULT 的过滤器,因为当startActivity() 和startActivityForResult() 方法处理Intent 时,默认情况下假定接受组件具有属性为CATEGORY_DEFAULT 的过滤器CATEGORY_DEFAULT。如果Activity 组件没有声明这样的过滤器,它将不会接收隐式Intent。
例如,下面的代码声明了一个Activity组件,它可以处理隐式Intent,其action属性为ACTION_SEND,数据类型为文本(text/plain)。
用户还可以创建包含多个和标签的过滤器。创建时,他们只需要确保组件能够处理过滤器定义的操作。
如果基于、标签组合处理多个Intent,则需要为此组件声明多个过滤器。
系统将使用这三个属性来将隐式Intent 与所有组件声明的过滤器进行比较。如果这三个属性都能匹配,系统就能够将隐式Intent传递给组件,因为如果多个应用程序的所有组件都匹配的话,就会弹出一个选择框,允许用户选择一个应用程序来处理这个隐式Intent。意图。
为了避免无意中启动其他Service,建议在应用程序中始终使用显示的Intent来启动服务,这样就不需要在AndroidManifest.xml文件中为Service声明过滤器。
Activity 过滤器必须在AndroidManifest.xml 文件中声明,也可以不声明,直接使用显示Intent 来唤起Activity 组件。
广播接收器的过滤器声明可以在AndroidManifest.xml文件中声明,也可以使用registerReceiver()方法动态注册。使用后,可以使用unregisterReceiver() 方法动态取消注册。
9. 过滤器声明示例
以下过滤器声明可以帮助您更好地理解。
第一个名为MainActivity的组件是应用程序的启动入口页面。当用户单击应用程序图标时,Activity 将启动。
android.intent.action.MAIN表示Activity是应用程序的启动入口,不需要Intent携带任何数据。 android.intent.category.LAUNCHER 表示将Activity的图标设置为手机主屏的应用程序图标。如果没有图标,请使用应用程序图标。第二个名为ShareActivity 的组件可以处理两种类型的隐式Intents,并且可以接受文本和媒体内容的共享操作。也就是说,如果一个隐式Intent可以匹配任意一个filter,那么Activity就可以被唤起。当然,你也可以通过显示Intent规范来直接启动它。
9. PendingIntent
PendingIntent是Intent的封装。它的主要功能是允许外部应用程序执行内部意图,就像它们在您的应用程序中一样。
PendingIntent通常用于以下场景。
当用户点击通知栏时,会执行该Intent(系统的NotificationManager执行的Intent)。详情请参阅此处。当用户操作悬浮在主屏幕中的widget时,Intent(主屏幕应用程序执行的Intent)被执行。具体可以参考这里的将来特定时间执行的Intent(系统的AlarmManager执行的Intent)是因为每个Intent对象都是针对特定的组件类别(Activity/Service/BroadcastReceiver)实例化的,所以在创建时PendingIntent,你也必须基于同样的因素来实例化,使用下面的方法来实例化PendingIntent。
PendingIntent.getActivity(),返回适用于Activity 组件的PendingIntent。 PendingIntent.getService() 返回适用于Service 组件的PendingIntent。 PendingIntent.getBroadcast() 返回适用于BroadcastReceiver 的PendingIntent。当然,官方还有其他方式获取PendingIntent对象。但是内部也是使用上述三个方法来获取实例化对象。
这三种方法都需要当前应用程序的上下文、需要封装的Intent以及一个或多个关于如何使用该Intent的标志(例如该Intent是否可以多次使用)。
Pending的具体使用这里不再讨论。如果需要了解具体用途,可以查看Notification中PendingIntent的使用以及浮动工具栏中PendingIntent的使用。
10. Intent匹配规则
如上所述,当发送隐式Intent时,系统会将其与设备中各个组件的过滤器进行匹配。匹配的属性包括操作、类别和数据。所有三个属性都是必需的。只有匹配成功才能唤起相应的组件。
10.1 Action匹配规则
过滤器可以声明无Action 属性或声明多个Action 属性。如下:
.隐式Intent中的Action属性可以匹配组件中某个过滤器的Action(如果一个过滤器声明了多个Action属性,则只需要匹配其中一个),则认为匹配成功。
如果过滤器没有声明Action属性,则只有没有设置Action属性的隐式Intent才能匹配成功。
10.2 Category匹配规则
过滤器可以不声明任何类别属性,也可以声明多个类别属性,如下所示:
.隐式Intent 中声明的类别必须全部与过滤器中的类别匹配才能被视为成功匹配。例如,Category属性设置为CATEGORY_BROWSABLE的隐式Intent也可以通过上述过滤器。也就是说,过滤器的Category属性内容必须大于或等于隐式Intent的Category属性,才能成功匹配隐式Intent。
如果隐式Intent 没有设置Category 属性,则它可以传递过滤器中的任何Category 匹配项。
10.3 Data匹配规则
过滤器可以声明无数据属性或多个数据属性,如下所示:
.每个Data属性可以指定数据的URI结构和数据MIME类型。 URI包括四部分:方案、主机、端口和路径。主机和端口一起也构成了权限(host:port)部分。
://:/例如:
content://192.168.0.1:8080/folder/subfolder/etc 在此URI 中,scheme 为content,主机为192.168.0.1,端口为8080,path 为folder/subfolder/etc。我们平时使用的网络URL就是这种格式。
在URI 中,每个组件都是可选的,但具有线性依赖关系
如果没有方案部分,则主机部分将被忽略。如果没有主机部分,则端口部分将被忽略。如果既没有主机部分也没有端口部分,则路径部分将被忽略。在进行URI匹配时,不是全部比较,而是局部比较,以下是URI匹配规则。
如果一个URI只声明了scheme部分,那么所有具有相同scheme的URI都会被匹配,而其他部分将不会被匹配。如果一个URI声明了scheme部分和authority部分,那么只有具有相同scheme和authority的URI才会匹配成功。路径部分不匹配。如果声明了URI 的所有部分,则只有具有相同部分的URI 才能成功匹配。注意:路径部分可以使用通配符(*),即用于匹配的路径部分。
匹配Data 时,MIME 类型和URI 都会匹配。匹配规则如下:
如果过滤器没有声明URI和MIME类型,则只有没有URI和MIME类型的不可见Intent才能匹配成功。如果过滤器中声明了URI,但未声明MIME 类型(无法从URI 中分析出MIME 类型),则只有URI 与过滤器URI 相同且不包含IME 类型的隐式Intent 才会匹配成功地。如果过滤器声明了MIME 类型但未声明URI,则只有包含相同MIME 类型但不包含URI 的隐式Intent 才会匹配成功。如果过滤器声明UR
I和MIME类型(既可以是直接设置,也可以是从URI分析出来),只有包含相同的URI和MIME类型的隐式Intent才能匹配成功注意:进行匹配时候必须以过滤器为单位进行匹配,不能跨过滤器匹配。如果一个过滤器声明了多个Action、Category、Data,隐式Intent包含的Action、Category、Data都能在过滤器中匹配到相应的属性即可,也就是说过滤器中声明的属性是大于或者等于Intent中包含的属性,Intent才能匹配成功OK,关于深入解析Android中的Intent与IntentFilter机制和的内容到此结束了,希望对大家有所帮助。
【深入解析Android中的Intent与IntentFilter机制】相关文章:
2.米颠拜石
3.王羲之临池学书
8.郑板桥轶事十则
用户评论
这个标题听起来挺专业的,我有点好奇 Intent 和 IntentFilter 这两样东西
有15位网友表示赞同!
要学习 Android 开发吗? 这个标题应该很有帮助!
有8位网友表示赞同!
以前只知道它们的作用,现在终于有时间来深入了解了。
有20位网友表示赞同!
期待作者能把 Intent 和 IntentFilter讲得通俗易懂!
有6位网友表示赞同!
想学 Android 的朋友们,要看一看这个标题的帖子哦!
有18位网友表示赞同!
感觉这是一个比较基础的概念讲解,挺适合新手入门学习的。
有13位网友表示赞同!
浅谈就能抓住重点,这篇文章应该介绍得比较全面。
有11位网友表示赞同!
我之前理解 Intent 和 IntentFilter 的概念不太完整,希望能从这篇文章中学到更多。
有18位网友表示赞同!
对 Android 开发感兴趣的朋友可以关注一下这个论坛的讨论!
有18位网友表示赞同!
标题虽然简单,但内容应该相当深入。期待作者的专业分享!
有16位网友表示赞同!
做 Android 开发的时候这些概念确实非常关键,一定要掌握好。
有13位网友表示赞同!
这篇文章能帮助我更全面地了解 Android 的开发逻辑吗?
有6位网友表示赞同!
希望能看到一些实际案例和代码实例,更容易理解 Intent 和 IntentFilter 的运用。
有6位网友表示赞同!
这个标题吸引了我,我想要看看 Intent 和 IntentFilter 的具体实现方法。
有20位网友表示赞同!
Android 开发越来越常用Intent 和 IntentFilter 了,这篇文章应该很有价值。
有10位网友表示赞同!
学习编程总是要从基础开始,这篇浅谈肯定会让我受益匪浅!
有13位网友表示赞同!
希望能看到针对不同场景的 Intent 和 IntentFilter 的应用技巧,更实用!
有14位网友表示赞同!
对于刚入门 Android 开发的人来说,这份解读应该是很好的指南!
有12位网友表示赞同!
期待作者能够结合实例讲解,让我的理解更加深刻!
有16位网友表示赞同!