回顾与总结:
- Intent能启动Activity,Service,BroadcastReceiver三大系统组件
- 指定Intent的Component属性就是显性定义Intent,只要为其赋予Component对象就行了。没有指定的即为隐性定义Intent,此时Intent所启动的组件能否启动取决于组件的<intent-filter>元素的配置:只要某个组件能满足的要求大于或等于Intent所指定的要求 ,那么该Intent就能启动
//第一种方式显示声明Intent ComponentName comp = new ComponentName(ThisClass.this,SecondClass.class); Intent intent = new Intent(); intent.setComponent(intent); //第二种方式显示声明Intent Intent intent = new Intent(ThisClass.this,SecondClass.class);
- 指定Intent的Component属性即是显性声明intent明确要启动哪个组件,被启动组件几乎无需配置<intent-filter>元素。此时,<intent-filter>中的Action,Category,Data,Type,Extra,Flag对于显性声明的Intent无效。
- Action代表该Intent要完成的一个操作,而Category则是对Action 的补充说明类别信息。一个Intent只能携带一个Action,却能携带多个Category。但intent-filter能配置多个Action元素且至少有一个默认的Category,当某个Intent携带的Action属性被多个组件响应时,程序会弹出请求画面交给用户选择
- Activity,service,receiver的子元素,能配置的要素有:0-N个action,0-N个category,0-1个data
- 指定Action,Category调用系统Activity
- Data,Type,Extra,Flag属性的设置
- 使用Intent创建Tab页面
- Intent一旦发出,Android都会准确找到相匹配的一个或多个Activity,Service或者BroadcastReceiver作响应。所以,不同类型的Intent消息不会出现重叠,即Broadcast的Intent消息只会发送给BroadcastReceiver,而决不会发送给Activity或者Service。由startActivity()传递的消息也只会发给Activity,由startService()传递的Intent只会发送给Service。
- 注册的action的名字为.intent.action.YOUR_ACTION_NAME。(试验:如果不采用package-name,调用时会出现找不到Activity的异常)经测试,没有这个异常。
- 在intent中传递的不是reference(指针),而是copy一份,我们修改对象,并不会影响已经copy进intent中bundle的数据,这点需要非常注意。
- activity的intent-filter中可以有多个category描述,其中CATEGORY_DEFAULT表示可以使用implicit intent调用,当我们增加此项声明后,本应用就出现在匹配的activity列表中。同样,对于通过action name来调用的,不指定包名和类名的,也属于implicit intent,同样需要进行CATEGORY_DEFAULT的声明,否则会出现ActivityNotFoundException的错误。如果activity没有在intent fliter中设置为CATEGORY_DEFAULT,我们可以用PackageManager获取匹配的activities的信息,分析后得到确切的包名和类名,通过explicit的方式唤起该activity。
此外Android说如果从launcher screen唤起时不需要DEFAULT,也就是此时acitivty只需MAIN和LAUNCHER,当然我们也可以DEFAULT设上。Android在DEFAULT上似乎有些繁杂,简单说如果我们不希望App被其他App通过implicit调用,我们就不要设置DEFAULT。
什么是Intent
Intent直译“意图”,是对操作执行的抽象描述。主要解决Android应用的各项组件之间的通讯。Intent负责对应用中一次操作的动作、动作涉及数据、附加数据进行描述,Android则根据此Intent的描述,负责找到对应的组件,将 Intent传递给调用的组件,并完成组件的调用。因此,Intent在这里起着一个媒体中介的作用,专门提供组件互相调用的相关信息,实现调用者与被调用者之间的解耦。总的来说:Intent具有组件激活和数据携带的功能。
Intent的构成
Intetn对象的组成:Action,Data,Category,Extras,Flags,Component name
Action:说明要执行的操作,是字符串常量,更多Action可以到帮助文档Intent类找到。用户也可以自己定义自己的Action常量。通常使用setAction()和getAction()来设置
注意的点:一个Intent最多只能设置一个Action常量,启动的组件的Intent-filter能配置多个Action常量
常用的Action:
ACTION_CALL | activity | 启动一个电话. |
ACTION_EDIT | activity | 显示用户编辑的数据. |
ACTION_MAIN | activity | 作为Task中第一个Activity启动 |
ACTION_SYNC | activity | 同步手机与数据服务器上的数据. |
ACTION_BATTERY_LOW | broadcast receiver | 电池电量过低警告. |
ACTION_HEADSET_PLUG | broadcast receiver | 插拔耳机警告 |
ACTION_SCREEN_ON | broadcast receiver | 屏幕变亮警告. |
ACTION_TIMEZONE_CHANGED | broadcast receiver | 改变时区警告. |
Data:是执行动作的URI和MIME类型,不同的动作有不同的数据规格。即通常来为Action属性提供操作的数据。通俗的讲:Action是ACTION_EDIT时,数据域将是文档的URI;Action是ACTION_CALL时,数据域是 tel: URI ,带有要拨打的电话号码;如果Action是 ACTION_VIEW,则数据域是http: URI。匹配到Intent的组件知道Intent所携带的数据类型是很重要的。因为不可能叫一个文本编辑的组件去播放视频。
注意的点:
- Data属性接受一个Uri对象,Uri对象用满足如下的字符串来表示:scheme://host:port/path 例如:content://com.android.contacts:8080/contacts/1
- Type属性即MIME类型,指定该Data所指定的Uri对应的MIME类型,这种MIME类型可以是任何自定义的MIME类型,只要符合abc/xyz格式的字符串就行了
- 数据类型也可以显式指定,比如setData()方法指定数据为URI,setType() 指定为MIME type,setDataAndType() 指定它既为URI又为MIME type。读取的时候URI用getData(),MIME type用getType()。但要注意如果分别设置Data属性,Type属性会相互覆盖。
MIME类型有2种形式:
1.1 单个记录的格式: vnd.android.cursor.item/vnd.yourcompanyname.contenttype,如:content://com.example.transportationprovider/trains/122(一条列车信息的uri)的MIME类型是vnd.android.cursor.item/vnd.example.rail
1.2 多个记录的格式:vnd.android.cursor.dir/vnd.yourcompanyname.contenttype,如:content://com.example.transportationprovider/trains (所有列车信息)的MIME类型是vnd.android.cursor.dir/vnd.example.rail
- 目标组件的<data>子元素只指定了android:scheme,android:host,android:port,android:path,那么Intent的Data属性的scheme,host,port,path要全部对应相同的属性值才可启动
- 目标组件的<data>子元素只指定了android:scheme,android:host,android:path,那么只要Intent的Data属性的scheme,host,path对应相同的属性值就能启动了
- 目标组件的<data>子元素只指定了android:scheme,android:host,android:port,那么只要Intent的Data属性的scheme,host,port对应相同的属性值就能启动了
- 目标组件的<data>子元素只指定了android:scheme,android:host,那么只要Intent的Data属性的scheme,host,对应相同的属性值就能启动了
- 目标组件的<data>子元素只指定了android:scheme,那么只要Intent的Data属性的scheme对应相同的属性值就能启动了
- 另外注意的是如果没有指定android :host属性,那么android:port,android:path,是起不到作用的。总的来说:Intent携带的Data属性要大于或等于data元素配置的要求就行了。
- 一个Intent能携带多个Category,Intent-filter要配置至少一个Category属性(就算Intent没添加Category属性,也应该在intent-filter配置一个Intent.CATEGORY_DEFAULT属性)
- 确定了component name,即显性定义了Intent,程序将不会根据Intent 的属性去寻找合适的组件。
Intent解析机制
application package的信息)来查找能处理这个Intent的component。在这个解析过程中,Android是通过Intent的action、type、category这三个属性来进行判断的,判断方法如下:
1.1 如果Intent指明定了action,则目标组件的IntentFilter的action列表中就必须包含有这个action,否则不能匹配;
1.2 如果Intent没有提供type,系统将从data中得到数据类型。和action一样,目标组件的数据类型列表中必须包含Intent的数据类型,否则不能匹配。
1.3 如果Intent中的数据不是content:类型的URI,而且Intent也没有明确指定type,将根据Intent中数据的scheme(比如 http:或者mailto:)进行匹配。同上,Intent 的scheme必须出现在目标组件的scheme列表中。
1.4 如果Intent指定了一个或多个category,这些类别必须全部出现在组建的类别列表中。比如Intent中包含了两个类别:LAUNCHER_CATEGORY和ALTERNATIVE_CATEGORY,解析得到的目标组件必须至少包含这两个类别。