第6章 Android应用核心Intent
(教学录像:39分钟)
一个Android程序由多个组件组成,各个组件之间使用Intent进行通信。Intent对象中包含组件名称、动作、数据等内容。根据Intent中的内容,Android系统可以启动需要的组件。
通过阅读本章,您可以:
★ 掌握Intent对象
★ 掌握Intent的使用
6.1 Intent对象
教学录像:光盘\TM\lx\6\Intent对象.exe
即使一个最简单的Android应用程序,也是由多个核心组件构成的。如果用户需要从一个Activity切换到另一个,则必须使用Intent来激活。实际上,Activity、Service和Broadcast Receiver这3种核心组件都需要使用Intent来进行激活。Intent用于相同或者不同应用程序组件间的后期运行时绑定。
对于不同的组件,Android系统提供了不同的Intent发送机制进行激活。
[√]Intent对象可以传递给Context.startActivity()或Activity.startActivityForResult()方法来启动Activity或者让已经存在的Activity去做其他任务。Intent对象也可以作为Activity.setResult()方法的参数,将信息返回给调用startActivityForResult()方法的Activity。
[√]Intent对象可以传递给Context.startService()方法来初始化Service或者发送新指令到正在运行的Service。类似的,Intent对象可以传递Context.bindService()方法来建立调用组件和目标Service之间的链接。它可以有选择地初始化没有运行的服务。
[√]Intent对象可以传递给Context.sendBroadcast()、Context.sendOrderedBroadcast()或Context.send- StickyBroadcast()等广播方法,使其被发送给所有感兴趣的BroadcastReceiver。
在各种情况下,Android系统寻找最佳的Activity、Service、BroadcastReceiver来响应Intent,并在必要时进行初始化。在这些消息系统中,并没有重叠。例如,传递给startActivity()方法的Intent仅能发送给Activity,而不会发送给Service或BroadcastReceiver。
在Intent对象中,包含了接收该Intent的组件感兴趣的信息(如执行的操作和操作的数据)以及Android系统感兴趣的信息(如处理该Intent的组件的类别和任何启动目标Activity的说明)。原则上讲,Intent包含组件名称、动作、数据、种类、额外和标记等内容,下面进行介绍。
6.1.1 组件名称(Component Name)
组件名称是指Intent目标组件的名称。它是一个ComponentName对象,由目标组件的完全限定类名(如com.mingrisoft.TestActivity)和组件所在应用程序配置文件中设置的包名(如com.mingrisoft)组合而成。组件名称的包名部分和配置文件中设置的包名不必匹配。
组件名称是可选的。如果设置,Intent对象会被发送给指定类的实例;如果没有设置,Android使用Intent对象中的其他信息决定合适的目标。
组件名称可以使用setComponent()、setClass()或setClassName()方法设置,使用getComponent()方法读取。
6.1.2 动作(Action)
Action是一个字符串,用来表示将要执行的动作。在广播Intent中,Action用来表示已经发生即将报告的动作。在Intent类中,定义了一系列动作常量,其目标组件包括Activity和Broadcast两类。下面分别进行介绍。
- 标准Activity动作
表6.1中列出了当前Intent类中定义的用于启动Activity的标准动作(通常使用Context.startActivity()方法),其中,最常用的是ACTION_MAIN和ACTION_EDIT。
表6.1 标准Activity动作说明
常 量 | 说 明 |
ACTION_MAIN | 作为初始的Activity启动,没有数据输入/输出 |
ACTION_VIEW | 将数据显示给用户 |
ACTION_ATTACH_DATA | 用于指示一些数据应该附属于其他地方 |
ACTION_EDIT | 将数据显示给用户用于编辑 |
ACTION_PICK | 从数据中选择一项,并返回该项 |
ACTION_CHOOSER | 显示Activity选择器,允许用户在继续前按需选择 |
ACTION_GET_CONTENT | 允许用户选择特定类型的数据并将其返回 |
ACTION_DIAL | 使用提供的数字拨打电话 |
ACTION_CALL | 使用提供的数据给某人拨打电话 |
ACTION_SEND | 向某人发送消息,接收者未指定 |
ACTION_SENDTO | 向某人发送消息,接收者已指定 |
ACTION_ANSWER | 接听电话 |
ACTION_INSERT | 在给定容器中插入空白项 |
ACTION_DELETE | 从容器中删除给定数据 |
ACTION_RUN | 无条件运行数据 |
ACTION_SYNC | 执行数据同步 |
ACTION_PICK_ACTIVITY | 挑选给定Intent的Activity,返回选择的类 |
ACTION_SEARCH | 执行查询 |
ACTION_WEB_SEARCH | 执行联机查询 |
ACTION_FACTORY_TEST | 工厂测试的主入口点 |
说明:关于表6.1内容的详细说明,请参考API文档中Intent类的说明。
注意:在使用表6.1中的动作时,需要将其转换为对应的字符串信息。例如,将ACTION_MAIN转换为android.intent.action.MAIN。
- 标准广播动作
表6.2中列出了当前Intent类中定义的用于接收广播的标准动作(通常使用Context.registerReceiver ()方法或者配置文件中的<receiver>标签)。
表6.2 标准广播动作说明
常 量 | 说 明 |
ACTION_TIME_TICK | 每分钟通知一次当前时间改变 |
ACTION_TIME_CHANGEDm | 通知时间被修改 |
ACTION_TIMEZONE_CHANGED | 通知时区被修改 |
ACTION_BOOT_COMPLETED | 在系统启动完成后发出一次通知 |
ACTION_PACKAGE_ADDED | 通知新应用程序包已经安装到设备上 |
ACTION_PACKAGE_CHANGED | 通知已经安装的应用程序包已经被修改 |
ACTION_PACKAGE_REMOVED | 通知从设备中删除应用程序包 |
ACTION_PACKAGE_RESTARTED | 通知用户重启应用程序包,其所有进程都被关闭 |
ACTION_PACKAGE_DATA_CLEARED | 通知用户清空应用程序包中的数据 |
ACTION_UID_REMOVED | 通知从系统中删除用户ID值 |
ACTION_BATTERY_CHANGED | 包含充电状态、等级和其他电池信息的广播 |
ACTION_POWER_CONNECTED | 通知设备已经连接外置电源 |
ACTION_POWER_DISCONNECTED | 通知设备已经移除外置电源 |
ACTION_SHUTDOWN | 通知设备已经关闭 |
说明:关于表6.2内容的详细说明,请参考API文档中Intent类的说明。
注意:在使用表6.2中的动作时,需要将其转换为对应的字符串信息。例如将ACTION_TIME _TICK转换为android.intent.action.TIME_TICK。
除了预定义的动作,开发人员还可以自定义动作字符串来启动应用程序中的组件。这些自定义的字符串应该包含一个应用程序包名作为前缀,如com.mingrisoft.SHOW_COLOR。
动作很大程度上决定了Intent其他部分的组成,特别是数据(data)和额外(extras)部分,就像方法名称决定了参数和返回值。因此,动作名称越具体越好,并且将它与Intent其他部分紧密联系。换句话说,开发人员应该为组件能处理的Intent对象定义完整的协议,而不是单独定义一个动作。
Intent对象中的动作使用setAction()方法设置,使用getAction()方法读取。
6.1.3 数据(Data)
Data表示操作数据的URI和MIME类型。不同动作与不同类型的数据规范匹配。例如,如果动作是ACTION_EDIT,数据应该是包含用来编辑的文档的URI;如果动作是ACTION_CALL,数据应该是包含呼叫号码的tel:URI。类似的,如果动作是ACTION_VIEW而且数据是http:URI,接收的Activity用来下载和显示URI指向的数据。
在将Intent与处理它的数据的组件匹配时,除了数据的URI,也有必要了解其MIME类型。例如,能够显示图片数据的组件不应用来播放音频文件。
在多种情况下,数据类型可以从URI中推断,尤其是content:URI。它表示数据存在于设备上并由ContentProvider控制。但是,类型信息也可以显式地设置到Intent对象中。setData()方法仅能指定数据的URI,setType()方法仅能指定数据的MIME类型,setDataAndType()方法可以同时设置URI和MIME类型。使用getData() 方法可以读取URI,使用getType()方法可以读取类型。
6.1.4 种类(Category)
Category是一个字符串,其中包含了应该处理当前Intent的组件类型的附加信息。在Intent对象中可以增加任意多个种类描述。与动作类似,在Intent类中也预定义了一些种类常量,其说明如表6.3所示。
表6.3 标准种类说明
常 量 | 说 明 |
CATEGORY_DEFAULT | 如果Activity应该作为执行数据的默认动作的选项,则进行设置 |
CATEGORY_BROWSABLE | 如果Activity能够安全地从浏览器中调用,则进行设置 |
CATEGORY_TAB | 如果需要作为TabActivity的选项卡,则进行设置 |
CATEGORY_ALTERNATIVE | 如果Activity应该作为用户正在查看数据的备用动作,则进行设置 |
CATEGORY_SELECTED_ALTERNATIVE | 如果Activity应该作为用户当前选择数据的备用动作,则进行设置 |
CATEGORY_LAUNCHER | 如果应该在顶层启动器中显示,则进行设置 |
CATEGORY_INFO | 如果需要提供其所在包的信息,则进行设置 |
CATEGORY_HOME | 如果是Home Activity,则进行设置 |
CATEGORY_PREFERENCE | 如果Activity是一个偏好面板,则进行设置 |
CATEGORY_TEST | 如果用于测试,则进行设置 |
CATEGORY_CAR_DOCK | 如果设备插入到car dock时运行Activity,则进行设置 |
CATEGORY_DESK_DOCK | 如果设备插入到desk dock时运行Activity,则进行设置 |
CATEGORY_LE_DESK_DOCK | 如果设备插入到模拟dock(低端)时运行Activity,则进行设置 |
CATEGORY_HE_DESK_DOCK | 如果设备插入到数字dock(高端)时运行Activity,则进行设置 |
CATEGORY_CAR_MODE | 如果Activity可以用于汽车环境,则进行设置 |
CATEGORY_APP_MARKET | 如果Activity允许用户浏览和下载新应用,则进行设置 |
说明:关于表6.3内容的详细说明,请参考API文档中Intent类的说明。
注意:在使用表6.3中的种类时,需要将其转换为对应的字符串信息。例如将CATEGORY_ DEFAULT转换为android.intent.category.DEFAULT。
addCategory()方法将种类增加到Intent对象中,removeCategory()方法删除上次增加的种类,getCategories()方法获得当前对象中包含的全部种类。
6.1.5 额外(Extras)
Extras是一组键值时,其中包含了应该传递给处理Intent的组件的额外信息。就像一些动作与特定种类的数据URI匹配,而一些与特定额外匹配。例如,动作为ACTION_TIMEZONE_CHANGED的Intent用time-zone额外来表示新时区;动作为ACTION_HEADSET_PLUG的Intent用state额外来表示耳机是否被插入,以及用name额外来表示耳机的类型。如果开发人员自定义一个SHOW_COLOR动作,则应该包含额外来表示颜色值。
Intent对象中包含了多个putXXX()方法(如putExtra()方法)用来插入不同类型的额外数据,也包含了多个getXXX()方法(如getDoubleExtra()方法)来读取数据。这些方法与Bundle对象有些类似。实际上,额外可以通过putExtras()和getExtras()方法来作为Bundle设置和读取。
6.1.6 标记(Flags)
Flags表示不同来源的标记。多数用于指示Android系统如何启动Activity(如Activity属于哪个Task)以及启动后如何对待(如它是否属于近期的Activity列表)。所有标记都定义在Intent类中。
说明:所有标记都是整数类型。
6.1.7 范例1:在Activity间使用Intent传递信息
例6.1 在Eclipse中创建Android项目,名称为6.1,在Activity中使用Intent来传递信息。(实例位置:光盘\TM\sl\6\6.1)
(1)在res\layout文件夹中创建布局文件firstactivity_layout.xml。在布局文件中,增加文本框、编辑框、按钮等控件,并修改其默认属性。修改完成后为布局代码如下:
- <?xml version="1.0" encoding="utf-8"?>
- <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:background="@drawable/background"
- android:orientation="vertical" >
- <TextView
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:gravity="center"
- android:text="@string/title"
- android:textColor="@android:color/black"
- android:textSize="30px" />
- <TextView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/username"
- android:textColor="@android:color/black"
- android:textSize="20px" />
- <EditText
- android:id="@+id/username"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:textColor="@android:color/black" >
- <requestFocus />
- </EditText>
- <TextView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/password"
- android:textColor="@android:color/black"
- android:textSize="20px" />
- <EditText
- android:id="@+id/password"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:inputType="textPassword"
- android:textColor="@android:color/black" />
- <Button
- android:id="@+id/ok"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/ok"
- android:textColor="@android:color/black"
- android:textSize="20px" />
- </LinearLayout>
(2)在res\layout文件夹中创建布局文件secondactivity_layout.xml。在布局文件中,增加文本框控件来显示用户输入的信息,并修改其默认属性。修改完成后布局代码如下所示:
- <?xml version="1.0" encoding="utf-8"?>
- <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:background="@drawable/background"
- android:orientation="vertical" >
- <TextView
- android:id="@+id/usr"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:textColor="@android:color/black"
- android:textSize="20px" />
- <TextView
- android:id="@+id/pwd"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:textColor="@android:color/black"
- android:textSize="20px" />
- </LinearLayout>
(3)编写FirstActivity类,用于从控件中接收用户输入的字符串并使用Intent进行传递,其代码如下:
- public class FirstActivity extends Activity {
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.firstactivity_layout); //设置页面布局
- Button ok = (Button) findViewById(R.id.ok); //通过id 值获得按钮对象
- ok.setOnClickListener(new View.OnClickListener() { //为按钮增加单击事件监听器
- @Override
- public void onClick(View v) {
- EditText username = (EditText) findViewById(R.id.username); //获得输入用户名的控件
- EditText password = (EditText) findViewById(R.id.password); //获得输入密码的控件
- Intent intent = new Intent(); //创建Intent 对象
- //封装用户名信息
- intent.putExtra("com.mingrisoft.USERNAME", username.getText().toString());
- intent.putExtra("com.mingrisoft.PASSWORD", password.getText().toString());//封装密码信息
- intent.setClass(FirstActivity.this, SecondActivity.class); //指定传递对象
- startActivity(intent); //将Intent 传递给Activity
- }
- });
- }
- }
}
(4)编写SecondActivity类,用于从Intent中获得传递的信息并在文本框中显示,其代码如下:
- public class SecondActivity extends Activity {
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.secondactivity_layout); //设置页面布局
- Intent intent = getIntent();//获得Intent
- String username = intent.getStringExtra("com.mingrisoft.USERNAME"); //获得用户输入的用户名
- String password = intent.getStringExtra("com.mingrisoft.PASSWORD"); //获得用户输入的密码
- TextView usernameTV = (TextView) findViewById(R.id.usr); //获得第二个Activity 的文本框控件
- TextView passwordTV = (TextView) findViewById(R.id.pwd); //获得第二个Activity 的文本框控件
- usernameTV.setText("用户名:" + username); //设置文本框内容
- passwordTV.setText("密码:" + password); //设置文本框内容
- }
- }
启动程序后,将显示如图6.1所示的数据输入界面。在“用户名”编辑框中输入“明日科技”,在“密码”编辑框中输入“123”,单击“提交”按钮将显示如图6.2所示的界面。
![]() | ![]() |
图6.1 输入数据界面 | 图6.2 显示数据界面 |
6.1.8 范例2:返回系统Home桌面
例6.2 在Eclipse中创建Android项目,名称为6.2,在Activity中使用Intent来返回Home桌面。(实例位置:光盘\TM\sl\6\6.2)
(1)在res\layout文件夹中修改布局文件main.xml。在布局文件中,只保留一个按钮控件,并修改其默认属性。修改完成后的布局代码如下:
- <?xml version="1.0" encoding="utf-8"?>
- <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:background="@drawable/background"
- android:orientation="vertical" >
- <Button
- android:id="@+id/home_button"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/home"
- android:textColor="@android:color/black" />
- </LinearLayout>
(2)编写HomeActivity类,获得布局文件中的按钮并为其增加单击事件监听器,为其设置Intent,代码如下:
- public class HomeActivity extends Activity {
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.main); //设置页面布局
- Button home = (Button) findViewById(R.id.home_button); //通过id值获得按钮对象
- home.setOnClickListener(new View.OnClickListener() { //为按钮增加单击事件监听器
- @Override
- public void onClick(View v) {
- Intent intent = new Intent(); //创建Intent对象
- intent.setAction(Intent.ACTION_MAIN); //设置Intent动作
- intent.addCategory(Intent.CATEGORY_HOME); //设置Intent种类
- startActivity(intent); //将Intent传递给Activity
- }
- });
- }
- }
启动程序后,将显示如图6.3所示的界面。单击“返回Home”按钮,将显示如图6.4所示的系统Home桌面。
![]() | ![]() |
图6.3 应用主界面 | 图6.4 系统Home桌面 |
6.2 Intent使用
教学录像:光盘\TM\lx\6\Intent使用.exe
Intent可以分成显式和隐式两类。
显式Intent通过组件名称来指定目标组件。由于其他应用程序的组件名称对于开发人员通常是未知的,显式Intent通常用于应用程序内部消息,例如Activity启动子Service或其他Activity。
隐式Intent不指定组件名称,通常用于激活其他应用程序中的组件。
Android发送显式Intent到指定目标类的实例。Intent对象中,仅有组件名称对于发送给哪个组件影响至关重要。
对于隐式Intent,则需要使用不同的策略。在缺乏指定目标时,Android系统必须找到处理Intent的最佳组件——单个Activity或者Service来执行请求动作或者一组BroadcastReceiver来响应广播通知。它是通过比较Intent对象内容和Intent过滤器来实现的。Intent过滤器是与组件关联的结构,它能潜在地接收Intent。过滤器宣传组件的能力并划分可以处理的Intent,它们打开可能接收宣传类型的隐式Intent的组件。如果组件没有任何Intent过滤器,但仅能接收显式Intent;如果组件包含过滤器,则可以接收显式和隐式类型的Intent。
在使用Intent过滤器测试Intent对象时,对象中仅有3个方面与其相关:
[√]动作。
[√]数据(包括URI和数据类型)。
[√]种类。
额外和标记在决定哪个组件可以接收Intent时并无作用。
6.2.1 Intent过滤器
Activity、Service和BroadcastReceiver能定义多个Intent过滤器来通知系统它们可以处理哪些隐式Intent。每个过滤器描述组件的一种能力以及该组件可以接收的一组Intent。实际上,过滤器接收需要类型的Intent、拒绝不需要类型的Intent仅限于隐式Intent。对于显式Intent,无论内容如何,总可以发送给其目标,过滤器并不干预。
对于能够完成的工作及显示给用户的界面,组件都有独立的过滤器。
Intent过滤器是IntentFilter类的实例。然而,由于Android系统在启动组件前必须了解组件的能力,Intent过滤器通常不在Java代码中进行设置,而是使用<intent-filter>标签写在应用程序的配置文件(AndroidManifest.xml)中(唯一的例外是调用Context.registerReceiver()方法动态注册BroadcastReceiver的过滤器,它们通常直接创建为IntentFilter对象)。
过滤器中包含的域与Intent对象中动作、数据和分类域相对应。过滤器对于隐式Intent在这3个方面分别进行测试。仅有通过全部测试时,Intent对象才能发送给拥有过滤器的组件。由于组件可以包含多个过滤器,Intent对象在一个过滤器上失败并不代表不能通过其他测试。下面对这些测试进行详细介绍。
- 动作测试
配置文件中的<intent-filter>标签将动作作为<action>子标签列出,例如:
- <intent-filter . . . >
- <action android:name="com.example.project.SHOW_CURRENT" />
- <action android:name="com.example.project.SHOW_RECENT" />
- <action android:name="com.example.project.SHOW_PENDING" />
- . . .
- </intent-filter>
如上所示,尽管Intent对象仅定义一个动作,在过滤器中却可以列出多个。列表不能为空,即过滤器中必须包含至少一个<action>标签,否则会阻塞所有Intent。
为了通过该测试,Intent对象中定义的动作必须与过滤器中列出的一个动作匹配。如果对象或者过滤器没有指定动作,结果如下:
[√]如果过滤器没有包含任何动作,即没有让对象匹配的东西,则任何对象都无法通过该测试。
[√]如果过滤器至少包含一个动作,则没有指定动作的对象自动通过该测试。
- 种类测试
配置文件中的<intent-filter>标签将分类作为<category>子标签列出,例如:
- <intent-filter . . . >
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.BROWSABLE" />
- . . .
- </intent-filter>
为了让Intent通过种类测试,Intent对象中每个种类都必须与过滤器中定义的种类匹配。在过滤器中可以增加额外的种类,但是不能删除任何Intent中的种类。
因此原则上讲,无论过滤器中如何定义,没有定义种类的Intent总是可以通过该项测试。然而,有一个例外。Android默认所有通过startActivity()方法传递的隐式Intent包含一个种类android.intent. category.DEFAULT(CATEGORY_DEFAULT常量)。因此,接收隐式Intent的Activity必须在过滤器中包含android.intent.category.DEFAULT(包含android.intent.action.MAIN和android.intent.category. LAUNCHER设置的是一个例外。它们标示Activity作为新任务启动并且显示在启动屏幕上,包含android.intent.category.DEFAULT与否均可)。
- 数据测试
配置文件中的<intent-filter>标签将数据作为<data>子标签列出,例如:
- <intent-filter . . . >
- <data android:mimeType="video/mpeg" android:scheme="http" . . . />
- <data android:mimeType="audio/mpeg" android:scheme="http" . . . />
- . . .
- </intent-filter>
每个<data>标签可以指定URI和数据类型(MIME媒体类型)。URI可以分成scheme、host、port和path几个独立的部分:
- scheme://host:port/path
例如下面的URI:
- content://com.example.project:200/folder/subfolder/etc
其中,scheme是content;host是com.example.project;port是200;path是folder/subfolder/etc。host和port一起组成了URI授权,如果host没有指定,则忽略port。
这些属性都是可选的,但是相互之间并非完全独立。如果授权有效,则scheme必须指定。如果path有效,则scheme和授权必须指定。
当Intent对象中的URI与过滤器中的URI规范比较时,它仅与过滤器中实际提到的URI部分相比较。例如,如果过滤器仅指定了scheme,所有具有该scheme的URI都能匹配该过滤器;如果过滤器指定了scheme和授权而没指定path,则不管path如何,具有该scheme和授权的URI都能匹配;如果过滤器指定了scheme、授权和path,则具有相同scheme、授权和path的URI能够匹配。然而,过滤器中的path可以包含通配符来允许部分匹配。
<data>标签中的type属性指定数据的MIME类型。在过滤器中,这比URI更常见。Internet对象和过滤器都能使用“”通配符来包含子类型,如“text/”或者“audio/*”。
数据测试比较Intent对象和过滤器中的URI和数据类型,其规则如表6.4所示。
表6.4 数据测试规则说明
说明:Intent对象数据类型的未指定也包括不能从URI中推断数据类型。同理,指定也包括能从URI中推断数据类型。
注意:对于表6.4中的第4种情况,如果Intent对象中包含content: 或file: URI,过滤器中未指定URI也可以通过测试。换句话说,如果组件过滤器仅包含数据类型,则假设其支持content:和file: URI。
如果Intent对象可以通过多个Activity或者Service的过滤器,则用户需要选择执行的组件;如果没有任何匹配,则报告异常。
6.2.2 范例1:使用包含预定义动作的隐式Intent
例6.3 在Eclipse中创建Android项目,名称为6.3,在Activity中使用包含预定义动作的隐式Intent启动另外一个Activity。(实例位置:光盘\TM\sl\6\6.3)
(1)在res\layout文件夹中创建布局文件firstactivity_layout.xml。在布局文件中保留一个按钮,并修改其默认属性,其代码如下:
- <?xml version="1.0" encoding="utf-8"?>
- <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- android:background="@drawable/background"
- android:orientation="vertical" >
- <Button
- android:id="@+id/button"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/button"
- android:textColor="@android:color/black" />
- </LinearLayout>
(2)在布局文件中添加文本框控件来显示字符串,并修改其默认属性。修改完成后布局代码如下所示:
- <?xml version="1.0" encoding="utf-8"?>
- <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- android:background="@drawable/background"
- android:orientation="vertical" >
- <TextView
- android:id="@+id/textView"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/text"
- android:textColor="@android:color/black"
- android:textSize="25px" />
- </LinearLayout>
(3)编写FirstActivity类,获得布局文件中的按钮控件并为其增加单击事件监听器。在监听器中传递包含动作的隐式Intent,其代码如下:
- public class FirstActivity extends Activity {
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.firstactivity_layout); //设置页面布局
- Button button = (Button) findViewById(R.id.button); //通过id值获得按钮对象
- button.setOnClickListener(new View.OnClickListener() { //为按钮增加单击事件监听器
- public void onClick(View v) {
- Intent intent = new Intent(); /创建Intent对象
- intent.setAction(Intent.ACTION_VIEW); //为Intent设置动作
- startActivity(intent); //将Intent传递给Activity
- }
- });
- }
- }
注意:在上面的代码中,并没有指定将Intent对象传递给哪个Activity。
(4)编写SecondActivity类,仅为其设置布局文件,其代码如下:
- public class SecondActivity extends Activity {
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.secondactivity_layout); //设置页面布局
- }
- }
(5)编写AndroidManifest.xml文件,为两个Activity设置不同的Intent过滤器,其代码如下:
- <manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.mingrisoft"
- android:versionCode="1"
- android:versionName="1.0" >
- <uses-sdk android:minSdkVersion="15" />
- <application
- android:icon="@drawable/ic_launcher"
- android:label="@string/app_name" >
- <activity android:name=".FirstActivity" >
- <intent-filter >
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
- </intent-filter>
- </activity>
- <activity android:name=".SecondActivity" >
- <intent-filter >
- <action android:name="android.intent.action.VIEW" />
- <category android:name="android.intent.category.DEFAULT" />
- </intent-filter>
- </activity>
- </application>
- </manifest>
(6)启动程序后,单击“转到下一个Activity”按钮,显示如图6.5所示的界面。
图6.5 选择发送方式界面
(7)选择“6.3”跳转到第二个Activity,界面如图6.6所示。
图6.6 第二个Activity界面
说明:由于有多种匹配ACTION_VIEW的方式,因此需要用户进行选择。
6.2.3 范例2:使用包含自定义动作的隐式Intent
在范例1中,讲述了使用系统中预定义的动作来定义Intent。开发人员还可以根据需要自定义动作。本范例将在范例1的基础上进行修改,使用自定义动作来启动隐式Intent。
例6.4 在Eclipse中创建Android项目,名称为6.4,在Activity中使用包含自定义动作的隐式Intent启动另外一个Activity。(实例位置:光盘\TM\sl\6\6.4)
(1)在例6.3的基础上,将FirstActivity类的代码修改为如下内容:
- public class FirstActivity extends Activity {
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.firstactivity_layout); //设置页面布局
- Button button = (Button) findViewById(R.id.button); //通过id值获得按钮对象
- button.setOnClickListener(new View.OnClickListener() { //为按钮增加单击事件监听器
- public void onClick(View v) {
- Intent intent = new Intent(); /创建Intent对象
- intent.setAction("test_action"); //为Intent设置动作
- startActivity(intent); //将Intent传递给Activity
- }
- });
- }
- }
(2)将AndroidManifest.xml文件代码修改为如下内容:
- <?xml version="1.0" encoding="utf-8"?>
- <manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.mingrisoft"
- android:versionCode="1"
- android:versionName="1.0" >
- <uses-sdk android:minSdkVersion="15" />
- <application
- android:icon="@drawable/ic_launcher"
- android:label="@string/app_name" >
- <activity android:name=".FirstActivity" >
- <intent-filter >
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
- </intent-filter>
- </activity>
- <activity android:name=".SecondActivity" >
- <intent-filter >
- <action android:name="test_action" />
- <category android:name="android.intent.category.DEFAULT" />
- </intent-filter>
- </activity>
- </application>
- </manifest>
(3)启动应用程序,如图6.7所示。单击“转到下一个Activity”按钮,如图6.8所示。此时并没有让用户选择处理隐式Intent的组件,而是直接跳转到第二个Activity。
![]() | ![]() |
图6.7 第一个Activity界面 | 图6.8 第二个Activity界面 |
6.3 经典范例
6.3.1 使用Intent拨打电话
例6.5 在Eclipse中创建Android项目,名称为6.5,实现拨打电话功能。(实例位置:光盘\TM\sl\6\6.5)
(1)在res\layout文件夹中打开布局文件main.xml。添加一个编辑框和一个按钮,并修改其默认属性,其代码如下:
- <?xml version="1.0" encoding="utf-8"?>
- <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- android:background="@drawable/background"
- android:orientation="vertical" >
- <EditText
- android:id="@+id/editText"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:inputType="phone"
- android:textColor="@android:color/black"
- android:textSize="25px" >
- <requestFocus />
- </EditText>
- <Buton
- android:id="@+id/button"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/call"
- android:textColor="@android:color/black"
- android:textSize="25px" />
- </LinearLayout>
(2)编写DialActivity,它从页面中获得用户输入的电话号码。通过为按钮增加单击事件监听器来完成拨号功能,其代码如下:
- public class DialActivity extends Activity {
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.main); //设置页面布局
- EditText numberTV = (EditText) findViewById(R.id.editText); //通过id值获得编辑框对象
- final String number = numberTV.getText().toString(); //获得用户输入的电话号码
- Button dial = (Button) findViewById(R.id.button); //通过id值获得按钮对象
- dial.setOnClickListener(new View.OnClickListener() {
- public void onClick(View v) {
- Intent intent = new Intent(); /创建Intent对象
- intent.setAction(Intent.ACTION_CALL); //为Intent设置动作
- intent.setData(Uri.parse("tel:" + number)); //为Intent设置数据
- startActivity(intent); //将Intent传递给Activity
- }
- });
- }
- }
(3)修改AndroidManifest.xml文件,增加拨打电话的权限,其代码如下:
- <?xml version="1.0" encoding="utf-8"?>
- <manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.mingrisoft"
- android:versionCode="1"
- android:versionName="1.0" >
- <uses-sdk android:minSdkVersion="15" />
- <application
- android:icon="@drawable/ic_launcher"
- android:label="@string/app_name" >
- <activity android:name=".DialActivity" >
- <intent-filter >
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
- </intent-filter>
- </activity>
- </application>
- <uses-permission android:name="android.permission.CALL_PHONE" />
- </manifest>
(4)运行应用程序,效果如图6.9所示。在编辑框中输入需要拨打的电话,单击“拨打电话”按钮就可以完成拨号功能。
图6.9 拨打电话界面
6.3.2 使用Intent打开网页
例6.6 在Eclipse中创建Android项目,名称为6.6,实现打开网页功能。(实例位置:光盘\TM\sl\6\6.6)
(1)在res\layout文件夹中打开布局文件main.xml。添加一个按钮,并修改其默认属性,其代码如下:
- <?xml version="1.0" encoding="utf-8"?>
- <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- android:background="@drawable/background"
- android:orientation="vertical" >
- <Button
- android:id="@+id/button"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/open"
- android:textColor="@android:color/black"
- android:textSize="25px" />
- </LinearLayout>
(2)编写WebActivity,它通过为按钮增加单击事件监听器来完成打开网页功能,其代码如下:
- public class WebActivity extends Activity {
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.main); //设置页面布局
- Button button = (Button) findViewById(R.id.button); //通过id值获得按钮对象
- button.setOnClickListener(new View.OnClickListener() {
- public void onClick(View v) {
- Intent intent = new Intent(); /创建Intent对象
- intent.setAction(Intent.ACTION_VIEW); //为Intent设置动作
- intent.setData(Uri.parse("http://www.google.com.hk")); //为Intent设置数据
- startActivity(intent); //将Intent传递给Activity
- }
- });
- }
- }
(3)修改AndroidManifest.xml文件,增加要启动的Activity。
(4)启动应用,其运行效果如图6.10所示。单击“打开网页”按钮,显示如图6.11所示的谷歌主页。
![]() | ![]() |
图6.10 打开网页界面 | 图6.11 谷歌主页 |
6.4 小 结
本章介绍的是Intent对象在Android中的作用。Intent对象用于实现不同组件之间的连接。一个Intent对象包含组件名称、动作、数据、种类、额外和标记等内容。Android系统可以根据开发人员在Intent中设置的内容选择合适的组件进行处理。在日常开发中,应该注意显式Intent和隐式Intent的应用场合。
6.5 实践与练习
编写Android程序,实现使用Intent播放视频(假设在SD卡中包含Test.m4v文件)的功能。(答案位置:光盘\TM\sl\6\6.7)
编写Android程序,实现使用Intent编辑通讯录信息(假设在通讯录中至少保存了一条记录)的功能。(答案位置:光盘\TM\sl\6\6.8)