本文为个人读书笔记,大部分为书中内容摘要。仅供记录和分享学习中遇到的需要留意的问题,如有相关版权问题请及时通知作者。
简介
Intent是Android程序中传输数据的核心对象
概述
Android程序中,主要由三种独立的组件组成,他们之间可以互相调用、协调工作。在这些组件之间的通信中,主要是由Intent协助完成的。Intent负责对应用中一次操作的动作、动作涉及数据、附加数据进行描述,Android则根据此Intent的描述,负责找到对应的组件,将Intent传递给调用的组件,并完成组件的调用,因此,Intent在这里起着一个媒体中介的作用,专门提供组件互相调用的相关信息,实现调用者与被调用者之间的解耦。
三种不同的Intent对象传输机制
Activity:通过将一个Intent对象传递给Context.startActivity()或Activity.startActivityForResult()启动一个活动或者使一个已存在的活动去做新的事情。
Service:通过将一个Intent对象传递给Context.startService(),初始化一个Service或者传递一个新的指令给正在运行的Service;类似的,将一个Intent对象传递给Context.bindservice(),可以建立调用组件和目标服务之间的连接。
BroadcastReceiver:通过将一个Intent对象传递给任何广播方法(Context.sendBroadcast()、Context.sendOrderedBroadcast()、Context.sendStickyBroadcast()等),都可以传递到所有感兴趣的广播接收者。
在每种传输机制下,Android程序会自动查找合适的Activity、Service、BroadcastReceiver来响应Intent,如果有必要的话初始化他们,这些消息系统之间没有重叠。
Intent对象的组成
Intent对象实质上是一个捆绑信息,包含对Intent有兴趣的组件的信息、Android系统有兴趣的信息。
组件名称
用来指定为处理Intent对象的组件,是一个CoponetName对象,是目标组件的完全限定类名和应用程序所在的包在清单文件中的名字,组件名称中的包部分不必一定和清单文件中的包名一样。
是可选的,如果设置了,Intent对象传递到指定类的实例;如果不设置,Android使用Intent中的其他信息来定位合适的目标组件。可以通过setComponet、setClass、setClassName方法设置,getComponent方法读取。
setComponent方法:为Intent设置组件
public
Intent setComponet(ComponentName
componet)
component:要设置的组件名称
返回值:Intent对象
setClass方法:为Intent设置要打开的Activity
public
Intent setClass(Context
packageContext
,Class<?>
cls
packageContext:当前Activity的this对象
cls:要打开的Activity的class对象
返回值:Intent对象
setClassName方法:为Intent设置要打开的Activity名称
public
Intent setClassName(Context
packageContext,String
className
)
packageContext:当前Activity的this对象
className:要打开的Activity的类名称
返回值:Intent对象
getComponent方法:获取与Intent相关的组件
public
ComponentName
getComponent()
返回值为与Intent相关的组件名称
动作
动作很大程度上决定了Intent如何构建,特别是数据data和附加信息extras,应该尽可能明确指定动作,并金币关联到其他Intent字段。也就是说,应该定义组件能够处理的Intent对象的整个协议,而不仅仅是单独的定义一个动作。
Intent类常用动作常量
动作常量 | 作用对象 | 描述 |
ACTION_CALL | Activity | 直接拨打电话 |
ACTION_DIAL | Activity | 打开拨打电话界面 |
ACTION_VIEW | Activity | 查看用户列表 |
ACTION_EDIT | Activity | 编辑用户列表 |
ACTION_HEADSET_PLUG | Activity | 耳机插拔 |
ACTION_MAIN | Activity | 在没有数据输入和输出时,默认的启动Activity |
ACTION_SENDTO | Activity | 给某人发送信息 |
ACTION_SYNC | Activity | 是移动设备的数据与服务器数据保持同步 |
ACTION_BATTERTY_LOW | BroadcastReceiver | 显示电量低的警告信息 |
ACTION_SCREEN_ON | BroadcastReceiver | 打开屏幕 |
ACTION_TIMEZONE_CHANGED | BroadcastReceiver | 修改时区设置 |
*Intent类还有很多动作常量。
开发人员可以自定义动作字符串,自定义动作字符串应该包含应用程序包名的前缀
一个Intent对象的动作通过setAction方法设置,getAction方法读取。
setAction:为Intent设置动作
public
Intent setAction(String
action)
action:要设置的动作名称,通常设置为AndroidAPI提供的动作常量
返回值:Intent对象
getAction:获取Intent的动作名称
public
Intent getAction()
返回值为String字符串,表示Intent的动作名称。
数据
data是作用与Intent上的数据的URI和数据的MIME类型,不同的动作有不同的数据规格。
当匹配一个Intent到一个能够处理数据的组件时,明确其数据类型(MIME)和URI很重要。
多数情况下,数据类型能够从URI中推测,特别是content:URIs,它表示位于设备上的数据且被内容提供者Content Provider控制,但是,类型也能够显式的设置。
setData:为Intent设置URI数据
public
Intent setData(Uri
data)
data:要设置的数据的URI
返回值为Intent对象
setType:为Intent设置数据的MIME类型
public
Intent setType(String
type)
type:要设置的MIME类型
返回值为Intent对象
setDataAndType:为Intent设置数据及其MIME类型
public
Intent setDataAndType(Uri
data,String
type)
data:要设置的数据的URI
type:要设置的数据的MIME类型
返回值为Intent对象
getData:获取与Intent相关的数据
public
Uri getData()
返回值为URI类型,表示获取到的与Intent相关数据的URI
getType:获取与Intent相关的数据的MIME类型
public
String getType()
返回值为String字符串,表示获取到的MIME类型
种类
用来作为被执行动作的附加信息,开发人员可以在一个Intent对象中指定任意数量的种类描述。Intent类中定义了一些种类常量。
Intent类的常用的种类常量
种类常量 | 描述 |
CATEGORY_DEFAULT | 默认的种类常量 |
CATEGORY_ALTERNATIVE | 表示当前的Intent是一系列可选动作中的一个,这些动作可以在同一块数据上执行 |
CATEGORY_BROWSABLE | 表示浏览器在特定条件下可以打开Activity |
CATEGORY_GADBET | 当前Activity可以被嵌入到充当配件宿主的其他Activity中 |
CATEGORY_HOME | Activity将显示桌面 |
CATEGORY_LAUNCHER | Intent的接受者应该在Launcher中作为顶级应用出现 |
CATEGORY_PREFERENCE | 目标Activity是一个选择面板 |
addCategory:为Intent添加种类信息
public
Intent addCategory(String
category)
category:要添加的种类信息,通常用AndroidAPI中提供的种类常量表示
返回值为Intent对象
removeCategory:从Intent中删除指定的种类信息
public
void
removeCategory(String
category)
category:要删除的种类信息
getCategories:获取所有与Intent相关的种类信息
public
Set<String>
getCategories()
返回值为字符串类型的泛型数组,表示所有与Intent相关的种类信息。
附加信息
额外的键值对信息应该传递到组件处理Intent,就像动作关联的特定种类数据URIs,也关联到某些特定的附加信息。Intent对象中有一系列的put...()方法用于插入何种附加数据,一系列的get...()方法用于读取数据,这些方法与Bundle对象的方法类似,实际上,附加信息可以作为一个Bundle对象使用putExtras方法和getExtras方法安装和读取
putExtras:为Intent添加附加信息
常用重载形式:
public
Intent putExtras(String
name,String
value)
name:附加信息的名称
value:附加信息的值
返回值为Intent对象
getExtras:获取Intent中的附加信息
public
Bundle
getExtras()
返回值为Bundle对象,用来存储获取到的Intent附加信息
标志
指示Android程序如何去启动一个活动,所有的标志都定义在Intent类中
常用的标志常量
标志常量 | 描述 |
FLAG_GRANT_READ_URI_PERMISSION | 对Intent数据具有读取权限 |
FLAG_GRANT_WRITE_URI_PERMISSION | 对Intent数据具有写入权限 |
FLAG_ACTIVITY_CLEAR_TOP | 如果在当前Task中有要启动的Activity,那么把该Activity之前的所有Activity都关掉,并把该Activity置前以避免创建Activity的实例 |
FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET | 将在Task的Activity Stack中设置一个还原点,当Task恢复时需要清理Activity |
FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS | 新的Activity不会再最近启动的Activity的列表中保存 |
FLAG_ACTIVITY_FORWARD_RESULT | 如果设置,并且这个Intent用于一个存在的Activity启动一个新的Activity,那么,这个作为答复目标的Activity将会传入到这个新的Activity中。这种方式下,新的Activity可以调用setResult(int),并且这个结果值将发送给那个作为答复目标的Activity |
FLAG_ACTIVITY_LAUNCHED_FROM_HISTROY | 这个标志一般不由应用程序代码设置,如果这个Activity是从历史记录里启动的,那么系统会自动设定 |
FLAG_ACTIVITY_MULTIPLE_TASK | 与FLAG_ACTIVITY_NEW_TASK结合使用。新的Task总是会启动来处理Intent,而不管是否已经有一个Task可以处理相同的事情。 |
FLAG_ACTIVITY_NEW_TASK | 系统会检查当前所有已创建的Task中是否有需要启动的Activity的Task,如果有,则在该Task上创建Activity;如果没有,则新建具有该Activity属性的Task,并在该新建的Task上创建Activity |
FLAG_ACTIVITY_NO_HISTORY | 新的Activity将不再历史Stack中保留,用户一旦离开它,这个Activity自动关闭 |
FLAG_ACTIVITY_NO_USER_ACTION | 作为新启动的Activity进入前台时,这个标志将在Activity暂停之前组织从最前方的Activity回调的onUserLeaveHint() |
由于默认的系统不包含图形Task管理功能,因此,尽量不要使用FLAG_ACTIVITY_MULTIPLE_TASK标识,除非能够提供给用户一种方式——可以返回到已经启动的task。
setFlags:为Intent设置标志
public
Intent setFlags(int
flaygs)
flags:要设置的标志,通常用AndroidAPI中提供的标志常量表示
返回Intent对象
addFlags:为Intent添加标志
public
Intent addFlags(int
flags)
flags:要添加的标志,通常用AndroidAPI中提供的标志常量表示
getFlags:获取Intent的标志
public
int
getFlags()
返回int类型数据,表示获取到的标志
Intent对象的解析
Intent可以分为两组,分别是显式Intent和隐式Intent
显式Intent:通过名字指定目标组件。常用于应用程序内部消息
隐式Intent:不指定目标的名字(组件名字字段是空的)。常用于激活其他应用程序中的组件。
当在Android程序中使用显式Intent时,Intent对象中只用组件名字内容就可以决定哪个组件应该获得这个Intent,而不用其他内容。而使用隐式Intent时,由于缺省指定目标,Android程序必须查找一个最适合的组件去处理Intent——一个活动或服务去执行请求动作,或一组广播接受者去响应广播声明,该过程是通过比较Intent对象的内容和Intent过滤器intent filters来完成的。Intent过滤器关联到潜在的接受Intent的组件,过滤器声明组件的能力和界定它能处理的Intents,它们打开组件接收声明的Intent类型的隐式Intent。如果一个组件没有任何Intent过滤器,它仅能接受现实的Intents,而声明了Intent过滤器的组件可以接收显示和隐式的Intents。
只有当一个Intent对象的动作、数据、种类3个方面都符合一个Intent过滤器,才被考虑是否接受Intent,而附加信息和标志在解析哪个组件接受Intent时不起作用。
Intent过滤器
活动、服务、广播接受者为了告知系统能够处理哪些Intent,他们可以有一个或多个Intent过滤器,Intent过滤器用<intent-filter>元素表示,每个过滤器描述组件的一种能力,即能够接收的一组Intent。它筛选掉的仅仅是不想要的隐式Intents。一个显式的Intent不管包含哪些信息,总是能够传递到它的目标组件;但是一个隐式Intent,仅当它能够通过组件的过滤器之一才能够传递给它。
一个组件能够做的每一个任务都有独立的过滤器。
一个Intent过滤器是一个IntentFilter类的实例,因为Android程序在启动一个组件之前必须知道它的能力,但是Intent过滤器通常不在Java代码中设置,而是在应用程序的主配置文件AndroidManifest.xml中以<intent-filter>元素设置。
广播接收者的过滤器通过调用Context.registerReceiver()方法动态的注册,它直接创建一个IntentFilter对象。
一个过滤器有对应于Intent对象的动作、数据、种类的字段,过滤器要检测隐式Intent对象的所有这3个字段,其中任何一个失败,Android程序都不会传递Intent给组件,然而,因为一个组件可以有多个Intent过滤器,一个Intent通不过组件的过滤器检测,其他的过滤器可能通过。
1、动作检测
在AndroidManifest.xml主配置文件中,使用<intent-filter>的<action>子元素列出所有动作信息。
一个<intent-filter>可以列出多个动作,这个动作列表不能为空,至少包含一个。否则将阻塞所有的Intents。
要通过动作检测,Intent对象中指定的动作必须匹配<intent-filter>过滤器的动作列表中的一个,而如果Intent对象或<intent-filter>过滤器没有指定一个动作,结果如下:
如果Intent对象没有指定动作,将自动通过检查<intent-filter>过滤器是否指定了动作
如果<intent-filter>没有指定动作,没有一个Intent将匹配,所有的Intent将检测失败,没有Intent能够通过过滤器。
2、数据检测
在AndroidManifest.xml主配置文件中,使用<intent-filter>的<data>子元素列出所有数据信息。
每个<data>子元素都需要指定一个数据类型(MIME)和一个URI。<data>元素中有4个属性scheme、host、port和path,分别对应于URI的每个部分。host和port一起构成URI的凭据authority,如果host没有指定,port也被忽略。这4个属性都是可选的,但并不是完全独立的。要使authority有意义,scheme必须也要指定,要使path有意义scheme和authority也都必须指定。
*当比较Intent对象和<intent-filter>过滤器的URI时,仅仅比较<intent-filter>过滤器中出现的URI属性。如果4个属性都指定了,就需要都匹配才算是匹配,path可以包含通配符。
<data>子元素中的type属性用来指定数据的MIME类型。Intent对象和<intent-filter>过滤器都可以用”*“通配符匹配类型字段。
在Android程序中进行数据检测时,既要检测URI,也要检测数据类型,规则如下:
一个Intent对象既不包含URI,也不包含数据类型:仅当<intent-filter>过滤器也不指定任何URIs和数据类型时,才不能通过检测;否则都能通过。
一个Intent对象包含URI,但不包含数据类型:仅当<intent-filter>过滤器也不指定数据类型,同时他们的URI匹配,才能通过检测。
一个Intent对象包含数据类型,但不包含URI:仅当<intent-filter>过滤器也只包含数据类型且与Intent相同,才通过检测。
一个Intent对象既包含URI,也包含数据类型(或数据类型能够从URI推断出):数据类型部分,只有与<intent-filter>过滤器中之一匹配才算通过;URI部分,它的URI要出现在<intent-filter>过滤器中,或者它有content:或file:URI,又或者<intent-filter>过滤器没有指定URI。
3、种类检测
在AndroidManifest.xml主配置文件中,使用<intent-filter>元素的<category>子元素列出所有种类信息。
对于一个Intent对象,如果要通过种类检测,Intent对象中的每个种类必须匹配过滤器中的一个,即过滤器能够列出额外的种类,但是Intent对象中的种类必须能够在过滤器中找到,即使一个种类在过滤器列表中没有,,就算种类检测失败。因此,原则上如果一个Intent对象中没有种类,应该总是通过种类测试,而不管<intent-filter>过滤器中有什么种类,但是有个例外,Android程序对待所有传递给Context.startActivity的隐式Intent,都至少包含”android.intent.category.DEFAULT“(对应CATEGORY_DEFAULT常量),因此Activity如果要接受隐式Intent,就必须在<intent-filter>过滤器中包含”android.intent.category.DEFAULT“
通用情况
在Android程序对Intent对象进行解析时,主要由两种通用情况。
1、在过滤器中指指定数据类型
组件能够从内容提供者或文件获取本地数据,因此,他们的过滤器仅列出数据类型,而不必明确指出 content:和file:scheme的名字。
2、在过滤器中指定一个scheme和一个数据类型
在过滤器中指定一个scheme和一个数据类型
使用Intent匹配
Intent对照着<intent-filter>过滤器匹配,不进去发现一个目标组件去激活,而且去发现设备上的组件的其他信息。
使用Intent传递数据
Intent对象时一个被动的数据结果保存一个将要执行的操作的抽象描述,或在广播的情况下,通常是某事已经发生并正在执行,它通常用来激活Activity、Service、BroadcastReceiver,并在他们之间传递数据。
无参数Activity跳转
使用startActivity方法实现,该方法的语法中有一个Intent对象作为参数,用来表示要执行的Intent,该Intent必须已经设置了要跳转到的Activity名称
public
void
startActivity(Intent
intent)
向下一个Activity传递数据
主要由两种情况,分别是将数据传递到打开的Activity中和得到新打开Activity关闭后返回的数据。
1、将数据传递到打开的Activity中
首先需要使用putExtras方法设置要传递的数据,然后使用响应的get...Extras(getStringExtra、getIntExtra等)方法获取传递的数据。如不确定出传递的数据类型,可以直接使用getExtras方法获取传递的数据,但是使用该方法获取到的数据是存储在Bundle对象中的。
2、得到新打开Activity关闭后返回的数据
如果要在Activity中得到新打开Activity关闭后返回的数据,首先需要使用系统提供的startActivityForResult(Intent intent,int requestCode)方法打开新的Activity;然后在新打开的Activity关闭前,使用setResult(int resultCode,Intent data)方法向前面的Activity返回数据;最后为了得到返回的数据,需要在前面的Activity中重写onActivityResult(int
requestCode,int resultCode,Intent data)方法实现。
startActivityForResult(Intent intent,int requestCode):以带有返回值的方式启动新的Activity
public
void
startAcctivityForResult(Intent
intent,int
requestCode
)
intent:要启动的intent对象
requestCode:请求码,根据业务需要由自己设定,用于标识请求来源。
setResult(int resultCode,Intent data):为要返回的Activity设置结果码
public
final
void
setResult(
int
reultCode,Intent
data)
resultCode:结果码,根据业务需要自己设定,通常采用RESULT_CANCELED或RESULT_OK表示
data:要返回的Activity所在的Intent对象
onActivityResult(int requestCode,int resultCode,Intent data):获取请求码和结果码获取新Activity中返回的数据
public
Intent
setData(Uri
data
)
requestCode:请求码,调用startActivityForResult方法传递过去的值
resultCode:结果码,标识返回数据来自哪个新Activity
data:Intent对象,用来去除新Activity返回的数据【9.4】