第9回 军师,求解Intent

刘关张三人拿着孔明给的PopupWindow小册子琢磨了好一阵子,学习过PopupWindow之后,三人在Android开发上终于有了小成。而孔明每日只是浇浇花,唱唱歌,上上茅坑啥的,闲时回答回答三兄弟提出的各种问题,日子过得也十分逍遥。

这一日早上,刘备忽然提议说:“我们干学这些Android知识也不是办法,不如实践一下如何?”

关羽说:“大哥所言甚是,所谓学以致用,听闻村东头有个叫曹操的广结天下Android开发大牛,开什么Android英雄大会,我们不如过去凑凑热闹,看看有什么项目可做的?”

张飞说:“村东头?这么近?那还等什么?我们赶快去瞧瞧吧!”

刘备说:“可是军师仍在睡梦之中,我们不如等军师醒了再一起走?”

张飞不耐烦道:“唉,军师每天不是睡觉就是上茅房,等他出来的时候黄花菜都凉了,我们还是先去,搞到些项目回来也好跟军师炫耀一下,哈哈!”

刘备点了点头,说:“那我们现在就出发!”

于是三人手挽着手,屁颠屁颠的来到村东头。只见村东头一片空地上扎满了帐篷,一片人山人海,热闹非凡的景象。

“大哥,怎么有这么多人啊?”张飞诧异道。

           刘备看了心也有点虚,说:“可能都是来凑热闹的,真正会开发的应该没几个吧?”

           关羽说:“我们还是赶紧去瞧瞧。”

           三人来到一个大帐篷前,只见一个书生打扮的人正在给人填表,刘备赶忙上去咨询,书生说:“我家主公一发英雄帖,各路Android开发大牛都云集此处,由于人员过多,所以我们必须筛选一下,给主公引荐真正的开发大牛。来这里填张表,然后等着叫你名参加面试。”

           刘关张三人你看看我,我看看你,都心想,还要面试啊。但事已至此也只能先硬着头皮报名参加了。

           当晚,孔明在家里翘着腿挖鼻孔,心想,那三大傻不知今天跑哪去了,今天连个被我吐槽的人都没有,好寂寞啊。没办法,只好继续挖鼻孔,正挖到兴高采烈,浑然忘我之际,见刘关张三人互相搀扶着走了进来。

           孔明问:“你们这是?为何一副很受伤的样子?”

           刘备二话不说冲过去抱住孔明的大腿,哭诉道:“军师啊,太欺负人啦,我们去曹操那里参加Android英雄大会,结果面试的时候被鄙视的七荤八素啊,骂得我好没尊严呀,呜呜呜,军师,我好委屈啊~”

           孔明:“唉,别哭啦,鼻涕都擦到我裤子上了,就你们这点斤两就想去参加Android英雄大会,说说都问你们什么题目了吧?”

           刘备说:“那考官让我好好解释一下Intent的用法和结构,我一紧张,啥叫Intent都忘了啊!”

           张飞问:“是呀,Android有Intent这个东西吗?考官瞎编的吧?”

           孔明说:“我晕啊……我说你们什么好,你们……没跟其他人说认识我吧?”

 

1.1.Intent简介

在第六回中,我们详细介绍了Activity的创建和使用。在解释如何解决多个Activity之间交互的问题时,多次提到了Intent。下面就让我们一起来看看Intent具体是什么。

           Intent负责对应用程序中一次操作的动作、动作涉及的数据、及附加的数据内容进行描述。Android会根据此Intent的描述,与过滤器Intent-filter匹配,将Intent传递给相对应的组件,并完成组件的调用。Intent不仅可以应用于应用程序之间,也可用于应用程序内部Activity/Service之间的交互。

孔明:可以看出Intent在应用程序中,主要起着一个媒体和中介的作用,专门提供组件互相调用的相关信息。Intent实现调用者与被调用这之间的解耦。

张飞:恩,虽然不太懂,但感觉好强大啊….

孔明:唉,就打个比方,老关、老张,你们一起去饭馆吃饭。你点了羊肉串,老关点了炒饭,这就是你们的Intent。然后,卖羊肉串的就开始烤串,厨师就炒饭。这样通过菜单,就实现了调用者与被调用者的解耦。

张飞:我懂了,卖羊肉串的intent-filter就是他会烤肉串、鸡翅、扇贝、板筋、肉筋、玉米、馒头片……

刘备:呃……咱还是吃饭去吧。

 

 

 

 


          

 

 

 

 

 

1.2. Intent的属性设置

Intent对象是一些信息的集合。它包含接收这个Intent的组件要使用的信息和一些Andoird系统要用到的信息。Intent主要有以下几个属性:

 

componentname属性

componentname表示Intent组件的名称。一个componentname对象,由两部分组成。第一部分是包名,注意一定要和Manifest中设置的包名相匹配,如“com.firstpeople.example.intent”;第二部分则是类名,要包含前面的包名,如“com.firstpeople.example.intent.HomeActivity”。component并不是必须的,通常Android会根据Intent中包含的其他属性的信息,例如action、data/type、category进行查找,并最终找到一个与之匹配的目标组件。但是如果指定了component,则不再执行上述的查找过程,直接使用它指定的组件。指定了这个属性之后,Intent的其他属性都是可选的。

 

action属性

action属性是一个字符串类型,表示该Intent要执行的动作或者广播broadcast中要报告的事件。Android在Intent类中,定义了一些标准action常量,如表9-1所示:

 

 

 

 

表9-1 action常量

常量

目标组件

说明

ACTION_CALL

Activity

直接拨打电话。

ACTION_EDIT

Activity

显示用户编辑的数据。

ACTION_MAIN

Activity

标识该Activity作为一个程序的开始。

ACTION_SYNC

Activity

同步手机与数据服务器上的数据。

ACTION_BATTERY_LOW

Broadcast Receiver

电池电量过低警告。

ACTION_HEADESET_PLUG

Broadcast Receiver

插拔耳机警告。

ACTION_SCREEN_ON

Broadcast Receiver

屏幕变亮警告。

ACTION_TIMEZONE_CHANGED

Broadcast Receiver

改变时区警告。

 

data属性

data属性是执行动作要操作的数据,Android中采用指向数据的一个URI来表示,不同的action应对应不同的data。例如,如果action是ACTION_EDIT,data中应该包含一个含有要显示文字的URI,如果action是ACTION_CALL,data应该是tel:URI这种形式。在将一个Intent与component相匹配的时候,知道data的URI中的MIME类型非常重要。一个只能显示图片的组件,不应用来处理音频数据。

张飞:二哥,啥是MIME数据类型啊?

关羽:MIME是指多用途互联网邮件扩充服务(Multipurpose Internet Mail Extensions)在Android中通过文件的MIME类型来判断有哪些应用程序可以处理这些文件。

张飞:……

关羽:就是一个字符串,指定了数据的类型,使Android能够识别。一般以[type]/[subtype]的形式出现,比如mp3文件,它的MIME type就是audio/x-mpeg,明白啦?

刘备:三弟,要淡定!

 

 

 

 

 

 

 

 


一般情况下,data的type可以从data的URI中获得,但是type也可以通过setType()或者setDataAndType方法明确指定,例如:

           Uri uri =Uri.parse("file:///sdcard/song.mp3");

intent.setDataAndType(uri," audio/x-mpeg");

 

category属性

category属性表示要执行action的类别。一个Intent可以有多个category。在Intent中定义了category常量,如表9-2所示:

 

 

表9-2 category常量

常量名

说明

CATEGORY_BROWSABLE

当Activity可以安全的被浏览器启动,用于显示一个连接中的数据,例如一个图片,或者一封email时,皆可以指定为BROWSABLE。

CATEGORY_GADGET

标识该Activity可以嵌入到另一个activity中。

CATEGORY_HOME

标识该Activity用于显示Home界面,也就是用户按下Home按钮后出现的界面。

CATEGORY_LAUNCHER

在启动程序时,让这个Activity出现在顶层。

CATEGORY_ALTERNATIVE

表示这个action应该包含在对某种数据的执行动作列表中。例如,操作一个联系人动作可以是浏览它,也可能是去编辑或删除它。

可以通过以下三个方法对category进行操作:addCategory()增加一个类别,removeCategory()删除一个类别,getCategories()获得支持的类别。

 

extras属性

extras属性指其他所有附加信息的集合。使用extras可以为组件提供扩展信息。就像有些action有其特定的dataURI一样,某些action也有其对应的extras。例如,要执行“发送电子邮件”这个动作,可以把电子邮件的标题、正文等分别保存在extras不同的键值当中。extra属性可以通过一系列put…()和get…()方法进行写入和读取,也可以使用Bundle类型进行数据传递,附加数据可以通过intent.putExtras()和intent.getExtras()进行传递。

张飞:Bundle是啥?

孔明:Bundle就是Android的一种key-value对,可以用来存储各种数据,例如,可以用(string, int)的形式存储int。

 

 

 

 

 


flags属性

flags属性用于指定Activity的启动方式和启动后系统对Activity的处理方式,在Intent类中定义的flags有20多个,常用如表9-3所示:

表9-3 flags常量

常量名

说明

FLAG_ACTIVITY_BROUGHT_TO_FONT

表示如果Activity在task中存在,就拿到最顶端,并不启动新的Activity。

FLAG_ACTIVIEY_CLEAR_TOP

如果Activity在task中存在,就将Activity之上所有的Activity清除掉。

FLAG_ACTIVITY_NEW_TASK

将Activity放到一个新的task中。

FLAG_ACTIVITY_NO_HISTORY

新启动的Activity将不会保存在History Stack中。

1.3. Intent的解析

这一节将对Intent的原理进行解析。需要说明的是,Intent根据是否指定了目标组件分为以下两类:

 

显式的Intent

在构造Intent时就设置component属性,直接指定Intent的接收者。由于应用程序的开发者一般不会获得另一应用程序的组件名,所以显式的Intent常用于应用程序内部的消息传递,例如,在程序内部开启一个新的Activity。对于显式的Intent,因为已经明确指定了目标组件,Android不需要再去做解析。

 

隐式的Intent

Intent发送者,在发送Intent时不知道,也不关心接收者是谁(component是缺省的)。隐式的Intent常用于应用程序之间的消息传递,这样做有利于降低发送者与接收者之间的耦合。Android需要解析那些隐式的Intent。通过用Intent的action、data(URI与type)和Category与组件的intent-filter进行比对,Android最终将Intent传递给可以处理此Intent的Activity、Broadcast Receier或者Service。Intent的extras与flags字段并不参与上述过程。

1.3.1.intent-filter

intent-filter不仅可以在XML中规定,也可以在代码中实现。因为Android系统在组件启动前就需要获得这个组件的intent-filter,所以intent-filter一般是在应用程序的manifast中以<intent-filter>元素的方式进行声明。如果组件不包含任何intent-filter,那么它只能接收显式的Intent。含有intent-filter的组件既可以接收显式的Intent也可以接收隐式的Intent。

Activity,service和broadcast receiver有时会声明一个甚至多个intent-filter,每个intent-filter都对组件进行了描述。例如,在Android自带的Note pad示例中,NoteEditor Activity声明了两个intent-filter,一个启动并显示一个特定的记录给用户查看或者编辑,另一个启动一个空的记录给用户编辑。

多个intent-filter中,只要通过了一个intent-filter就可以将Intent投递到组件。下面将具体介绍Intent的匹配规则。

1.3.2.action 匹配

如果Intent指定了action,则目标组件的intent-filter的action列表中必须包含有该action,否则不能匹配。下面通过一段代码介绍如何匹配action,如下所示:

action匹配代码清单9-3-2:

<intent-filter>

                      ……

                      <actionandroid:name="android.intent.action.MAIN" />  //action MAIN标示程序入口

                      <actionandroid:name="com.firstpeople.example.intent.SHOW_CURRNET" />

                      <actionandroid:name="com.firstpeople.example.intent.SHOW_LAST" />

                      ……

</intent-filter>

由上述代码所示,一个intent-filter可以列出多个action,而一个Intent对象只能指定一个action。如果一个intent-filter没有<action>元素,它将阻止所有Intent通过。另一方面,如果一个Intent没有指定action,它可以与任何含有<action>元素的intent-filter匹配

张飞:啊啊啊啊,这些action,老夫怎么都没见过?

关羽:“android.intent.action.MAIN”是前面提到的ACTION_MAIN的全拼,而其他两个则是自定义action。理论上任何字符串,都可以作为action,但是自定义action最好以应用程序的包名作为开头。

张飞:怎么不早说….

 

 

 

 

 

 


1.3.3.category 匹配

如果Intent指定了一个或多个category,这些category必须全部出现在intent-filter的category列表中,否则不能匹配。下面通过一段代码介绍如何匹配category,如下所示:

category匹配代码清单9-3-3:

<intent-filter>

                      ……

                      <categroyandroid:name="android.intent.category.DEFAULT" />

                      <categroy android:name="android.intent.category.ALTERNATIVE" />

                      ……

</intent-filter>

如果一个Intent没有指定category,那么该Intent总能通过category测试。需要注意的是,Android认为所有隐式的Intent都默认含有一个category,即“android.intent.category.DEFAULT”,因此所有希望接收隐式Intent的组件都应在其intent-filter内包含“android.intent.category.DEFAULT”。

1.3.4.data 匹配

类似于action和category,data也是intent-filter中的子节点,可以设置多个data节点,也可以一个都不设置。data的匹配至关重要,因为这说明了该组件支持的数据格式,例如,一个只支持图片查看的应用需要将含有音乐格式数据的Intent过滤掉。下面通过一段代码介绍如何匹配data,如下所示:

data匹配代码清单9-3-4:

<intent-filter>

                      ……

                      <dataandroid:mimeType="video/mpeg" android:scheme=”content”……/>

                      <dataandroid:mimeType="audio/*”android:sheme=”http”……/>

                      ……

</intent-filter>

           每个data元素如下所示:

data节点代码清单9-3-4所示:

<data

android:mimetype=”string”

android:scheme=”string”

                      android:host=”string”         

android:port=”string”          

android:path=”string”

                      android:pathPattern=”string”

                      android:pathPrefix=”string”/>

 

data节点可以指定一个mimeType属性和一些URI属性,如下所示:

 

           mimetype属性

这个属性指定了数据的MIME类型。其子类型可用星号通配符(*)来代替,表示能够与任何子类型匹配,例如,“audio/*”。

 

URI属性

l  scheme:用于指定URI中的scheme部分。至少要给intent-filter设置一个scheme属性,否则其他的URI属性就都没有意义了。需要注意的是,scheme匹配时是大小写敏感的,要始终使用小写字母来指定scheme。

l  host:这个属性定义了URI的主机部分,除非给出scheme属性,否则这个属性没有意义。

l  port:这个属性定义了URI的端口部分,只有当intent-filter指定了scheme和host属性时该属性才有意义。host与port一起构成了URI的authority。

l  path、pathPrefix、pathPattern:path属性指定一个完整的路径,这个路径会和Intent对象中的路径进行匹配。pathPrefix属性指定了部分路径,它会跟Intent对象中路径的初始部分进行匹配。pathPattern属性也要和Intent路径进行完整匹配,但是可以包含 (*)和(.*)通配符。

           在intent-filter中这些属性都是可选的,同时也是相互依赖的。如果没有给指定scheme属性,那么所有其他URI属性都将被忽略;如果没有指定host属性,那么port属性和所有path属性也将被忽略。

           Intent对象中的URI将按“scheme://host:port/path or pathPrefixor pathPattern”的格式解析成几个独立属性,例如:“content://com.firstpeople.example.intent:200/folder/subfolder/content”的属性是:

l  schema=”content:”

l  host=”com.firstpeople.example.intent”

l  port=”200”

l  path=” folder/subfolder/content”

包含在同一个<intent-filter>元素中所有的<data>节点只会对该intent-filter起作用,例如:

<intent-filter>

……

<dataandroid:mimeType="video/mpeg" android:scheme=”content”/>

……

</intent-filter>

<intent-filter>

           ……

           <dataandroid:mimeType="video/mpeg" />

           <data android:sheme=”content”/>

           ……

</intent-filter>

二者的效果是相同的。

 

URI匹配规则

当Intent对象的URI和intent-filter中的URI进行匹配时,只对列在intent-filter中的属性进行比较。例如:如果一个intent-filter只指定了一个scheme,那么所有包含该scheme的URI的Intent都能匹配。如果一个intent-filter指定了scheme和authority,没有指定path,那么所有包含此scheme和authority的Intent都认为是匹配的。

孔明:URI匹配在实际开发中,不如mimeType用途广泛,大家了解即可。

 

 

 

 


data匹配规则

Android会对Intent对象中的URI和datatype与intent-filter指定的URI和datatype进行比较,比较规则如下:

l 如果Intent没有指定URI和datatype,那么只有当intent-filter也未指定URI和datatype时,才能匹配。

l 如果Intent只有URI,没有data type(且datatype不能从URI中推断出来),那么只有当filter的URI与Intent的URI相匹配,且filter中并未指定mimeType时,才认为是匹配的。这种情况只限于不指向实际数据的URI,例如:“tel:55555”或“mailto:abc@gmail.com”,换句话说,这些URI本身就是数据,而不是指向数据的地址。

l 如果Intent只有datatype没有URI,那么只有当intent-filter中列出相同的data type且没有指定URI时,才能匹配。

l 如果Intent既有datatype或者data type可以从URI中推断出来,也有URI,那么匹配时存在两种情况:(1)data type必须要与intent-filter中列出的data type相匹配,且URI也必须匹配,这才认为Intent与intent-filter是匹配。(2)如果data的URI是“content:”或者“file:”,intent-filter也没有指定scheme,且data type与intent-filter中的data type匹配,这时才认为Intent与intent-filter是匹配。因为对Android来说content和file这两种scheme是最常见的,就被当成缺省值来对待。

需要注意的是如果一个Intent可以被多个Activity或者Service匹配,用户可能会被询问要使用哪个组件;如果没有找到任何一个组件,则会抛出异常。

1.3.5.intent-filter实例

在写一个intent-filter作为一个系统的公共接口时有一些注意事项,如下所示:

intent-filter代码清单9-3-5:

<!--小飞飞:低调!才是最牛的炫耀!!-->

<intent-filter>

<!--选择一个Android自带的action-->

<action android:name="android.intent.action.SEND"/>

<!--一定要添加default category -->

<categoryandroid:name="android.intent.category.DEFAULT" />

<!--指定data type -->

<dataandroid:mimeType="image/*" />

<!--如果需要的话,指定data的来源 -->

<dataandroid:shceme="http" />

</intent-filter>

下面将要介绍Service和Broadcast Receiver的intent-filter配置。

 

音乐播放器Service的intent-filter代码清单9-3-5

<!--小羽羽:我只管好我自己的码,别人的码跟我没有任何关系。-->

<intent-filter>

<actionandroid:name="android.intent.action.VIEW" />

<!-- 增加default category,接收隐式的intent -->

<category android:name="android.intent.category.DEFAULT"/>

<!--可以处理所有的audio类型-->

<dataandroid:mimeType="audio/*" />

</intent-filter>

该段代码使用了缺省的data URI属性,仍然可以接收URI是“content:”或者“file:”类型的Intent,使播放器支持播放本地文件。

 

处理SD卡状态变化的BroadcastReceiver的intent-filter代码清单9-3-5:

<!--小备备:好马不安二鞍,烈女不编代码。-->

<intent-filter>

<actionandroid:name="android.intent.action.MEDIA_MOUNTED"/>

<actionandroid:name="android.intent.action.MEDIA_UNMOUNTED"/>

<actionandroid:name="android.intent.action.MEDIA_SHARED"/>

<action android:name="android.intent.action.MEDIA_REMOVED"/>

<actionandroid:name="android.intent.action.MEDIA_EJECT"/>

<categoryandroid:name="android.intent.category.DEFAULT" />

<dataandroid:scheme="file" />

</intent-filter>

该段代码指定了data,但是并未指定data type,与上述data匹配规则所述情况2一致。

1.4. 使用Intent

前面介绍了Intent的基本原理,本节将要详细介绍Intent的使用方法。

1.4.1.Intent的使用方式

Intent主要有以下几种使用方式:

l  通过Context.startActivity()或者Activity.startActivityForResult()启动一个新的Activity,或者让一个已存在的Activity做一些新的操作。

l  通过Context.startService()启动一个服务或者通过Context.bindService与后台服务交互。

l  通过广播如Context.sendBroadcast()或Context.sendOrderedBroadCast()方法发送给Broadcast receiver。

1.4.2.使用显式的Intent

正向前面所说的,显式的Intent一般用于在程序内部启动Activity。于是张飞写了个小程序来描述他的一天,顺便验证一下学习成果。

HomeActivity.java代码清单9-4-2  :

/**

 * 使用显式的Intent

 *           ­­­——记我的一天

 * @author张飞:因为我要活着,不吃怎么行啊?人生啊,总是会碰到这样那样的烦心事,大

吃一顿也是一天,小吃一顿也是一天,就让自己大吃一天吧。

 */

publicclass HomeActivity extends Activity implements OnClickListener {

    @Override

    public void onCreate(BundlesavedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.homelayout);

        Button button =(Button)findViewById(R.id. restaurantButton);

                     //设置监听器

        button.setOnClickListener(this);

    }

    @Override

    public void onClick(View v) {

        switch (v.getId()) {

                                //点击吃饭按钮

case  R.id.restaurantButton:

                                          //构造intent

                Intent intent = new Intent();

                //设置组件名称

                intent.setComponent(newComponentName(getApplication(), RestaurantActivity.class));

                                          //启动餐馆activity

                startActivity(intent);

                break;

           default:

                break;

        }

    }

}

图9-1 显式的Intent实例

点击“吃饭”按钮,就会启动RestaurantActivity,如下图9-2所示:

图9-2 RestaurantActivity的界面一

           Android设置组件名称的方法有:

publicIntent setComponent(ComponentName component);

publicIntent setClass(Context packageContext, Class<?> cls);

publicIntent setClassName (Context packageContext, String className);

public Intent setClassName (StringpackageName, String className);

实际上,虽然有这么多的设置方法,但是在Intent内部标识组件名称的只有一个component,有这么多方法的原因是component有多种重载的构造函数。在程序内部启动Activity设置Intent如下所示:

显式的Intent设置代码清单9-4-2:

Intentintent = new Intent();

intent.setClass(getApplication(),NewActivity.class);

intent.setClassName(getApplication(),NewActivity.class.getName());

intent.setClassName(getApplication().getPackageName(),NewActivity.class.getName());

intent.setComponent(newComponentName(getApplication(), NewActivity.class));

intent.setComponent(new

ComponentName(getApplication(),NewActivity.class.getName()));

intent.setComponent(newComponentName(getApplication().getPackageName(),NewActivity.class.getName()));

startActivity(intent); 

需要注意的是为避免拼写错误,在设置Intent时,因尽量避免直接使用字符串常量作为参数。

1.4.3.使用自定义action

又经过一番奋战,张飞终于完善了点餐系统,它通过自定义action来实现程序内部的跳转,并使用extra传递附加信息,代码如下所示:

RestaurantActivity.java代码清单9-4-3:

/**

* 使用自定义action

*            ­­­——蚝情壮翅点餐系统

* @author张飞:因为我要写代码着,不吃怎么行啊?人生啊,总是会碰到这样那样的烦心事,

吃烤鸡翅也是一顿,吃小白菜也是一顿,就让自己吃烤鸡翅吧。

*/

public class RestaurantActivity extendsActivity implements OnClickListener {

// 泡面的蛮文原来是这么写的,受教了!——刘备

RadioButton intentNoodlesRadio = null;

RadioButton chickenWingRadio = null;

Button okButton = null;

EditText requestEditor = null;

//烤串和泡面的自定义action

static final String ACTION_BARBECUE =

"com.firstpeople.examples.intent.explicit.ACTION_BARBECUE";

static final String ACTION_NOODLE =

"com.firstpeople.examples.intent.explicit.ACTION_NOODLE";

           @Override

public void onCreate(BundlesavedInstanceState) {

   super.onCreate(savedInstanceState);

   setContentView(R.layout.restaurantlayout);

   intentNoodlesRadio = (RadioButton)findViewById(R.id.instantNoodlesRadio);

                      chickenWingRadio= (RadioButton)findViewById(R.id.checkenWingRadio);

                      okButton= (Button)findViewById(R.id.okButton);

                      requestEditor= (EditText)findViewById(R.id.requestEdit);

                     //设置监听器

                      okButton.setOnClickListener(this);

           }

           @Override

           public void onClick(View v) {

              switch (v.getId()) {

                     //点击点菜按钮

                                 case  R.id.okButton:

Intentintent = new Intent();

//将顾客的特殊要求放入Extra中,key设为“request”

           intent.putExtra("request",requestEditor.getText().toString());

            //如果选择鸡翅

            if(chickenWingRadio.isChecked()){

                                                     intent.setAction(ACTION_BARBECUE);

                                          }

                                           //如果选择泡面

                                          else{

                                                     intent.setAction(ACTION_NOODLE);

                                           }

                                           //使用隐式intent启动Activity

                                           startActivity(intent);

                                          break;

                                default:

break;

                 }

            };

}

运行程序,结果如图9-3所示:

图9-3 RestaurantActivity的界面二

           如图9-3所示,张飞的要求是“越辣越好”,点击“点菜”按钮后,将使用隐式的Intent启动BarbequeActivity。为了能正确获得Intent,需要在manifast中为BarbequeActivity设置intent-filter,如下代码所示:

设置intent-filter代码清单9-4-3

<activityandroid:name=".BarbecueActivity"android:label="@string/restaurant_name">

<intent-filter>

<actionandroid:name="com.firstpeople.examples.intent.explicit.ACTION_BARBECUE"/>

<!--一定要有category.DEFAULT -->

<categoryandroid:name="android.intent.category.DEFAULT" />

</intent-filter>

</activity>

孔明:需要注意的是,intent-filter里面的action字符串常量千万不要写错,因为这个在编译时不会被检查,运行时又没有异常,查找bug就会很麻烦。

 

 

 

 

 


BarbecueActivity.java代码清单9-4-3:

/**

* BarbecueActivity

*            ­­­——我爱Barbecue

* @author小飞飞:红烧鸡翅膀我喜欢吃!

                小明明:但是你老娘说你快升天!

小飞飞:越快升天所以越要更多吃,如果现在不吃以后没机会再吃!

小明明:你真的快升天?

小飞飞:我真的快升天!

合:如果现在不吃以后没机会再吃!

*/

public class BarbecueActivity extendsActivity {

TextView barbecueTextView = null;

@Override

public void onCreate(Bundle savedInstanceState){

super.onCreate(savedInstanceState);

setContentView(R.layout.barbecuelayout);

barbecueTextView =(TextView)findViewById(R.id.barbecueTextView);

                      //获得Extra中存储的信息,

String fromExtra =getIntent().getExtras().getString("request");

barbecueTextView.append(fromExtra);

};

}

运行程序,结果如图9-4所示:

图9-4 Barbeque界面

可以出,该代码通过设置Intent的extra属性成功地将张飞的要求传到了BarbequeActivity。

刘备:在一个Activity中,我们可以通过getIntent()方法获得启动该Activity的Intent。

 

          

 

1.4.4.使用Intent调用系统组件

为丰富生活,张飞对“我的一天”进行了增强,使用Intent直接调用呼叫组件。当张飞点击图9-1中的“打逗逗”按钮就可以直接给逗逗打电话了,如下代码所示:

           HomeActivity.java的onClick()代码清单9-4-4

/**

* @author 小飞飞:大哥,你别偷吃我的鸡翅!做码农要厚道!

*/

@Override

public void onClick(View v) {

   switch (v.getId()) {

                     //点击吃饭按钮

case R.id.restaurantButton:

            Intent intent = new Intent();

            //尽量以这种方式指定Component,避免拼写出错

intent.setComponent(newComponentName(getApplication(), RestaurantActivity.class));

            startActivity(intent);

            break;

case  R.id.punchDouDouButton:

           //将电话直接写入data的URI中

            Uri uri = Uri.parse("tel://123456");

            //隐式构造intent

            Intent it = newIntent(Intent.ACTION_CALL, uri);

//呼叫逗逗

startActivity(it);

            break;

       default:

            break;

   }

}

图9-5 “打逗逗”界面

将Intent的Action设置为为Intent.ACTION_CALL就可以直接将电话拨打出去,但需要在mainfast中增加permission:"android.permission.CALL_PHONE"。下面列出了几个常用的action供大家参考:

 

浏览网页

Uri uri =Uri.parse("http://www.google.com"); 
Intent it  = new Intent(Intent.ACTION_VIEW,uri); 
startActivity(it); 

 

打开录音机

Intent it = newIntent(Media.RECORD_SOUND_ACTION); 
startActivity(it); 

 

打开联系人列表

Intent i = new Intent(); 
i.setAction(Intent.ACTION_GET_CONTENT); 
i.setType("vnd.android.cursor.item/phone"); 
startActivityForResult(i, REQUEST_TEXT); 

1.4.5.使程序成为公共接口

刘备看了张飞的程序深受启发,决定自己也写个程序。通过让程序成为系统的公共接口使其可以直接发送编辑好的短信。

CustomSms.java代码清单9-4-5:

/**

* @author 小备备:曾经有一份真挚的鸡翅膀放在我面前,我没有珍惜,等被张飞吃掉后我才后

                                            悔莫及,人世间最痛苦的事莫过于此。如果上天能够给我一个再吃一次的机

                                            会,我会对那个鸡翅膀说三个字:我要吃。如果非要在这句话上加上一个期

                                            限,我希望是……吃一万年!

*/

public class CustomSms extendsActivity implements OnClickListener {

Button smsButton = null;

@Override

public void onCreate(BundlesavedInstanceState) {

   super.onCreate(savedInstanceState);

   setContentView(R.layout.mainlayout);

                      smsButton = (Button)findViewById(R.id.buttonSendSms);

                      smsButton.setOnClickListener(this);

}

@Override

public void onClick(View v) {

   switch (v.getId()) {

case  R.id.buttonSendSms:

                                           //获得启动本Activity的URI,例如"smsto:number"

                                           Uriuri = getIntent().getData();

                                           //使用ACTION_VIEW启动短信程序,避免再次选择程序

                                           Intentit = new Intent(Intent.ACTION_VIEW, uri);

                                           //使用getSchemeSpecificpart()获得smsto:之后的number

                                           Stringnumber = uri.getSchemeSpecificPart();

                                           //发送短信使用ACTION_VIEW的方式时,对Data的URI解析有误

                                           //需要将号码直接用address的方式传入Intent,否则将不会显示联系人

                                           it.putExtra("address",number);

                                           //这句千万不能忘!——刘备

                                           it.putExtra("sms_body","今天该你请客了,呵呵");

                                           //进入短信发送界面

                                           startActivity(it);

                                           break;

default:

break;

   }

}

}

运行程序,结果如图9-7所示:

图9-6  CustomSms界面

图9-7  选择程序界面

           点击“发送蹭饭短信”按钮,就可以直接发送预先写好的短信,如图9-8所示:

图9-8 短信发送界面

为使这个程序能够获得发送短信的Intent,在程序的manifest中增加intent-filter如下:

CustomSms的intent-filter代码清单9-4-5

<intent-filter>

           <actionandroid:name="android.intent.action.SENDTO" />

           <dataandroid:scheme="smsto" />

           <categoryandroid:name="android.intent.category.DEFAULT" />

</intent-filter>

与发送短信类似,通过增加相应的intent-filter,可以对系统中产生的各种Intent进行过滤:

 

对HTTP请求的Intent进行过滤

<intent-filter>

<actionandroid:name="android.intent.action.VIEW" />

<dataandroid:scheme="http" />

<category android:name="android.intent.category.DEFAULT"/>

</intent-filter>

 

过滤图片分享Intent

<intent-filter>

<actionandroid:name="android.intent.action.SEND" />

<dataandroid:mimeType="image/*" />

<categoryandroid:name="android.intent.category.DEFAULT" />

</intent-filter>

 

对通话的Intent进行过滤

<intent-filter >

<actionandroid:name="android.intent.action.CALL_PRIVILEGED" />

<categoryandroid:name="android.intent.category.DEFAULT" />

<dataandroid:scheme="tel" />

</intent-filter>

1.5. 玄德有话说

张飞:如果有两个Activity,从Activity1跳转到Activity2,那么还能从Activity2回到Activity1么?

刘备:当然可以,在Activity2中使用startActivity()不就行了么?

孔明:这个做法不太规范。还有更好的方法,在Activity2中直接使用startActivityForResult(),就行了。

张飞:什么意思?

孔明:在Activity2中,setResult()之后调用finish()结束Activity,在Activity1中使用onActivityResult()进行监听,就行了。

 

刘备:我听说intent-filter还有一个priority属性,是怎么回事?

孔明:这个会决定BroadCastReceiver接收广播的顺序,具体在后面章节会有介绍

 

张飞:我的程序为什么收不到Intent?

孔明:Android默认所有隐式的Intent都包含默认类别,你是否加了<categoryandroid:name="android.intent.category.DEFAULT" />?

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值