第6章 Android应用核心Intent

tb教学录像:39分钟)

一个Android程序由多个组件组成,各个组件之间使用Intent进行通信。Intent对象中包含组件名称、动作、数据等内容。根据Intent中的内容,Android系统可以启动需要的组件。

通过阅读本章,您可以:

★ 掌握Intent对象

★ 掌握Intent的使用

6.1 Intent对象

tb教学录像:光盘\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两类。下面分别进行介绍。

  1. 标准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。

  1. 标准广播动作

表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。在布局文件中,增加文本框、编辑框、按钮等控件,并修改其默认属性。修改完成后为布局代码如下:

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3. android:layout_width="match_parent"
  4. android:layout_height="match_parent"
  5. android:background="@drawable/background"
  6. android:orientation="vertical" >
  7. <TextView
  8. android:layout_width="fill_parent"
  9. android:layout_height="wrap_content"
  10. android:gravity="center"
  11. android:text="@string/title"
  12. android:textColor="@android:color/black"
  13. android:textSize="30px" />
  14. <TextView
  15. android:layout_width="wrap_content"
  16. android:layout_height="wrap_content"
  17. android:text="@string/username"
  18. android:textColor="@android:color/black"
  19. android:textSize="20px" />
  20. <EditText
  21. android:id="@+id/username"
  22. android:layout_width="match_parent"
  23. android:layout_height="wrap_content"
  24. android:textColor="@android:color/black" >
  25. <requestFocus />
  26. </EditText>
  27. <TextView
  28. android:layout_width="wrap_content"
  29. android:layout_height="wrap_content"
  30. android:text="@string/password"
  31. android:textColor="@android:color/black"
  32. android:textSize="20px" />
  33. <EditText
  34. android:id="@+id/password"
  35. android:layout_width="match_parent"
  36. android:layout_height="wrap_content"
  37. android:inputType="textPassword"
  38. android:textColor="@android:color/black" />
  39. <Button
  40. android:id="@+id/ok"
  41. android:layout_width="wrap_content"
  42. android:layout_height="wrap_content"
  43. android:text="@string/ok"
  44. android:textColor="@android:color/black"
  45. android:textSize="20px" />
  46. </LinearLayout>

(2)在res\layout文件夹中创建布局文件secondactivity_layout.xml。在布局文件中,增加文本框控件来显示用户输入的信息,并修改其默认属性。修改完成后布局代码如下所示:

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3. android:layout_width="match_parent"
  4. android:layout_height="match_parent"
  5. android:background="@drawable/background"
  6. android:orientation="vertical" >
  7. <TextView
  8. android:id="@+id/usr"
  9. android:layout_width="wrap_content"
  10. android:layout_height="wrap_content"
  11. android:textColor="@android:color/black"
  12. android:textSize="20px" />
  13. <TextView
  14. android:id="@+id/pwd"
  15. android:layout_width="wrap_content"
  16. android:layout_height="wrap_content"
  17. android:textColor="@android:color/black"
  18. android:textSize="20px" />
  19. </LinearLayout>

(3)编写FirstActivity类,用于从控件中接收用户输入的字符串并使用Intent进行传递,其代码如下:

  1. public class FirstActivity extends Activity {
  2. @Override
  3. protected void onCreate(Bundle savedInstanceState) {
  4. super.onCreate(savedInstanceState);
  5. setContentView(R.layout.firstactivity_layout); //设置页面布局
  6. Button ok = (Button) findViewById(R.id.ok); //通过id 值获得按钮对象
  7. ok.setOnClickListener(new View.OnClickListener() { //为按钮增加单击事件监听器
  8. @Override
  9. public void onClick(View v) {
  10. EditText username = (EditText) findViewById(R.id.username); //获得输入用户名的控件
  11. EditText password = (EditText) findViewById(R.id.password); //获得输入密码的控件
  12. Intent intent = new Intent(); //创建Intent 对象
  13. //封装用户名信息
  14. intent.putExtra("com.mingrisoft.USERNAME", username.getText().toString());
  15. intent.putExtra("com.mingrisoft.PASSWORD", password.getText().toString());//封装密码信息
  16. intent.setClass(FirstActivity.this, SecondActivity.class); //指定传递对象
  17. startActivity(intent); //将Intent 传递给Activity
  18. }
  19. });
  20. }
  21. }

}

(4)编写SecondActivity类,用于从Intent中获得传递的信息并在文本框中显示,其代码如下:

  1. public class SecondActivity extends Activity {
  2. @Override
  3. protected void onCreate(Bundle savedInstanceState) {
  4. super.onCreate(savedInstanceState);
  5. setContentView(R.layout.secondactivity_layout); //设置页面布局
  6. Intent intent = getIntent();//获得Intent
  7. String username = intent.getStringExtra("com.mingrisoft.USERNAME"); //获得用户输入的用户名
  8. String password = intent.getStringExtra("com.mingrisoft.PASSWORD"); //获得用户输入的密码
  9. TextView usernameTV = (TextView) findViewById(R.id.usr); //获得第二个Activity 的文本框控件
  10. TextView passwordTV = (TextView) findViewById(R.id.pwd); //获得第二个Activity 的文本框控件
  11. usernameTV.setText("用户名:" + username); //设置文本框内容
  12. passwordTV.setText("密码:" + password); //设置文本框内容
  13. }
  14. }

启动程序后,将显示如图6.1所示的数据输入界面。在“用户名”编辑框中输入“明日科技”,在“密码”编辑框中输入“123”,单击“提交”按钮将显示如图6.2所示的界面。

228-1 228-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。在布局文件中,只保留一个按钮控件,并修改其默认属性。修改完成后的布局代码如下:

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3. android:layout_width="match_parent"
  4. android:layout_height="match_parent"
  5. android:background="@drawable/background"
  6. android:orientation="vertical" >
  7. <Button
  8. android:id="@+id/home_button"
  9. android:layout_width="wrap_content"
  10. android:layout_height="wrap_content"
  11. android:text="@string/home"
  12. android:textColor="@android:color/black" />
  13. </LinearLayout>

(2)编写HomeActivity类,获得布局文件中的按钮并为其增加单击事件监听器,为其设置Intent,代码如下:

  1. public class HomeActivity extends Activity {
  2. @Override
  3. protected void onCreate(Bundle savedInstanceState) {
  4. super.onCreate(savedInstanceState);
  5. setContentView(R.layout.main); //设置页面布局
  6. Button home = (Button) findViewById(R.id.home_button); //通过id值获得按钮对象
  7. home.setOnClickListener(new View.OnClickListener() { //为按钮增加单击事件监听器
  8. @Override
  9. public void onClick(View v) {
  10. Intent intent = new Intent(); //创建Intent对象
  11. intent.setAction(Intent.ACTION_MAIN); //设置Intent动作
  12. intent.addCategory(Intent.CATEGORY_HOME); //设置Intent种类
  13. startActivity(intent); //将Intent传递给Activity
  14. }
  15. });
  16. }
  17. }

启动程序后,将显示如图6.3所示的界面。单击“返回Home”按钮,将显示如图6.4所示的系统Home桌面。

229-1 229-2
图6.3 应用主界面 图6.4 系统Home桌面

6.2 Intent使用

tb教学录像:光盘\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对象在一个过滤器上失败并不代表不能通过其他测试。下面对这些测试进行详细介绍。

  1. 动作测试

配置文件中的<intent-filter>标签将动作作为<action>子标签列出,例如:

  1. <intent-filter . . . >
  2. <action android:name="com.example.project.SHOW_CURRENT" />
  3. <action android:name="com.example.project.SHOW_RECENT" />
  4. <action android:name="com.example.project.SHOW_PENDING" />
  5. . . .
  6. </intent-filter>

如上所示,尽管Intent对象仅定义一个动作,在过滤器中却可以列出多个。列表不能为空,即过滤器中必须包含至少一个<action>标签,否则会阻塞所有Intent。

为了通过该测试,Intent对象中定义的动作必须与过滤器中列出的一个动作匹配。如果对象或者过滤器没有指定动作,结果如下:

[√]如果过滤器没有包含任何动作,即没有让对象匹配的东西,则任何对象都无法通过该测试。

[√]如果过滤器至少包含一个动作,则没有指定动作的对象自动通过该测试。

  1. 种类测试

配置文件中的<intent-filter>标签将分类作为<category>子标签列出,例如:

  1. <intent-filter . . . >
  2. <category android:name="android.intent.category.DEFAULT" />
  3. <category android:name="android.intent.category.BROWSABLE" />
  4. . . .
  5. </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与否均可)。

  1. 数据测试

配置文件中的<intent-filter>标签将数据作为<data>子标签列出,例如:

  1. <intent-filter . . . >
  2. <data android:mimeType="video/mpeg" android:scheme="http" . . . />
  3. <data android:mimeType="audio/mpeg" android:scheme="http" . . . />
  4. . . .
  5. </intent-filter>

每个<data>标签可以指定URI和数据类型(MIME媒体类型)。URI可以分成scheme、host、port和path几个独立的部分:

  1. scheme://host:port/path

例如下面的URI:

  1. 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 数据测试规则说明 232-1

说明: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。在布局文件中保留一个按钮,并修改其默认属性,其代码如下:

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3. android:layout_width="fill_parent"
  4. android:layout_height="fill_parent"
  5. android:background="@drawable/background"
  6. android:orientation="vertical" >
  7. <Button
  8. android:id="@+id/button"
  9. android:layout_width="wrap_content"
  10. android:layout_height="wrap_content"
  11. android:text="@string/button"
  12. android:textColor="@android:color/black" />
  13. </LinearLayout>

(2)在布局文件中添加文本框控件来显示字符串,并修改其默认属性。修改完成后布局代码如下所示:

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3. android:layout_width="fill_parent"
  4. android:layout_height="fill_parent"
  5. android:background="@drawable/background"
  6. android:orientation="vertical" >
  7. <TextView
  8. android:id="@+id/textView"
  9. android:layout_width="wrap_content"
  10. android:layout_height="wrap_content"
  11. android:text="@string/text"
  12. android:textColor="@android:color/black"
  13. android:textSize="25px" />
  14. </LinearLayout>

(3)编写FirstActivity类,获得布局文件中的按钮控件并为其增加单击事件监听器。在监听器中传递包含动作的隐式Intent,其代码如下:

  1. public class FirstActivity extends Activity {
  2. @Override
  3. protected void onCreate(Bundle savedInstanceState) {
  4. super.onCreate(savedInstanceState);
  5. setContentView(R.layout.firstactivity_layout); //设置页面布局
  6. Button button = (Button) findViewById(R.id.button); //通过id值获得按钮对象
  7. button.setOnClickListener(new View.OnClickListener() { //为按钮增加单击事件监听器
  8. public void onClick(View v) {
  9. Intent intent = new Intent(); /创建Intent对象
  10. intent.setAction(Intent.ACTION_VIEW); //为Intent设置动作
  11. startActivity(intent); //将Intent传递给Activity
  12. }
  13. });
  14. }
  15. }

注意:在上面的代码中,并没有指定将Intent对象传递给哪个Activity。

(4)编写SecondActivity类,仅为其设置布局文件,其代码如下:

  1. public class SecondActivity extends Activity {
  2. @Override
  3. protected void onCreate(Bundle savedInstanceState) {
  4. super.onCreate(savedInstanceState);
  5. setContentView(R.layout.secondactivity_layout); //设置页面布局
  6. }
  7. }

(5)编写AndroidManifest.xml文件,为两个Activity设置不同的Intent过滤器,其代码如下:

  1. <manifest xmlns:android="http://schemas.android.com/apk/res/android"
  2. package="com.mingrisoft"
  3. android:versionCode="1"
  4. android:versionName="1.0" >
  5. <uses-sdk android:minSdkVersion="15" />
  6. <application
  7. android:icon="@drawable/ic_launcher"
  8. android:label="@string/app_name" >
  9. <activity android:name=".FirstActivity" >
  10. <intent-filter >
  11. <action android:name="android.intent.action.MAIN" />
  12. <category android:name="android.intent.category.LAUNCHER" />
  13. </intent-filter>
  14. </activity>
  15. <activity android:name=".SecondActivity" >
  16. <intent-filter >
  17. <action android:name="android.intent.action.VIEW" />
  18. <category android:name="android.intent.category.DEFAULT" />
  19. </intent-filter>
  20. </activity>
  21. </application>
  22. </manifest>

(6)启动程序后,单击“转到下一个Activity”按钮,显示如图6.5所示的界面。

234-1 图6.5 选择发送方式界面

(7)选择“6.3”跳转到第二个Activity,界面如图6.6所示。

234-2 图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类的代码修改为如下内容:

  1. public class FirstActivity extends Activity {
  2. @Override
  3. protected void onCreate(Bundle savedInstanceState) {
  4. super.onCreate(savedInstanceState);
  5. setContentView(R.layout.firstactivity_layout); //设置页面布局
  6. Button button = (Button) findViewById(R.id.button); //通过id值获得按钮对象
  7. button.setOnClickListener(new View.OnClickListener() { //为按钮增加单击事件监听器
  8. public void onClick(View v) {
  9. Intent intent = new Intent(); /创建Intent对象
  10. intent.setAction("test_action"); //为Intent设置动作
  11. startActivity(intent); //将Intent传递给Activity
  12. }
  13. });
  14. }
  15. }

(2)将AndroidManifest.xml文件代码修改为如下内容:

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <manifest xmlns:android="http://schemas.android.com/apk/res/android"
  3. package="com.mingrisoft"
  4. android:versionCode="1"
  5. android:versionName="1.0" >
  6. <uses-sdk android:minSdkVersion="15" />
  7. <application
  8. android:icon="@drawable/ic_launcher"
  9. android:label="@string/app_name" >
  10. <activity android:name=".FirstActivity" >
  11. <intent-filter >
  12. <action android:name="android.intent.action.MAIN" />
  13. <category android:name="android.intent.category.LAUNCHER" />
  14. </intent-filter>
  15. </activity>
  16. <activity android:name=".SecondActivity" >
  17. <intent-filter >
  18. <action android:name="test_action" />
  19. <category android:name="android.intent.category.DEFAULT" />
  20. </intent-filter>
  21. </activity>
  22. </application>
  23. </manifest>

(3)启动应用程序,如图6.7所示。单击“转到下一个Activity”按钮,如图6.8所示。此时并没有让用户选择处理隐式Intent的组件,而是直接跳转到第二个Activity。

236-1 236-2
图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。添加一个编辑框和一个按钮,并修改其默认属性,其代码如下:

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3. android:layout_width="fill_parent"
  4. android:layout_height="fill_parent"
  5. android:background="@drawable/background"
  6. android:orientation="vertical" >
  7. <EditText
  8. android:id="@+id/editText"
  9. android:layout_width="match_parent"
  10. android:layout_height="wrap_content"
  11. android:inputType="phone"
  12. android:textColor="@android:color/black"
  13. android:textSize="25px" >
  14. <requestFocus />
  15. </EditText>
  16. <Buton
  17. android:id="@+id/button"
  18. android:layout_width="wrap_content"
  19. android:layout_height="wrap_content"
  20. android:text="@string/call"
  21. android:textColor="@android:color/black"
  22. android:textSize="25px" />
  23. </LinearLayout>

(2)编写DialActivity,它从页面中获得用户输入的电话号码。通过为按钮增加单击事件监听器来完成拨号功能,其代码如下:

  1. public class DialActivity extends Activity {
  2. @Override
  3. protected void onCreate(Bundle savedInstanceState) {
  4. super.onCreate(savedInstanceState);
  5. setContentView(R.layout.main); //设置页面布局
  6. EditText numberTV = (EditText) findViewById(R.id.editText); //通过id值获得编辑框对象
  7. final String number = numberTV.getText().toString(); //获得用户输入的电话号码
  8. Button dial = (Button) findViewById(R.id.button); //通过id值获得按钮对象
  9. dial.setOnClickListener(new View.OnClickListener() {
  10. public void onClick(View v) {
  11. Intent intent = new Intent(); /创建Intent对象
  12. intent.setAction(Intent.ACTION_CALL); //为Intent设置动作
  13. intent.setData(Uri.parse("tel:" + number)); //为Intent设置数据
  14. startActivity(intent); //将Intent传递给Activity
  15. }
  16. });
  17. }
  18. }

(3)修改AndroidManifest.xml文件,增加拨打电话的权限,其代码如下:

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <manifest xmlns:android="http://schemas.android.com/apk/res/android"
  3. package="com.mingrisoft"
  4. android:versionCode="1"
  5. android:versionName="1.0" >
  6. <uses-sdk android:minSdkVersion="15" />
  7. <application
  8. android:icon="@drawable/ic_launcher"
  9. android:label="@string/app_name" >
  10. <activity android:name=".DialActivity" >
  11. <intent-filter >
  12. <action android:name="android.intent.action.MAIN" />
  13. <category android:name="android.intent.category.LAUNCHER" />
  14. </intent-filter>
  15. </activity>
  16. </application>
  17. <uses-permission android:name="android.permission.CALL_PHONE" />
  18. </manifest>

(4)运行应用程序,效果如图6.9所示。在编辑框中输入需要拨打的电话,单击“拨打电话”按钮就可以完成拨号功能。

238-1 图6.9 拨打电话界面

6.3.2 使用Intent打开网页

例6.6 在Eclipse中创建Android项目,名称为6.6,实现打开网页功能。(实例位置:光盘\TM\sl\6\6.6)

(1)在res\layout文件夹中打开布局文件main.xml。添加一个按钮,并修改其默认属性,其代码如下:

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3. android:layout_width="fill_parent"
  4. android:layout_height="fill_parent"
  5. android:background="@drawable/background"
  6. android:orientation="vertical" >
  7. <Button
  8. android:id="@+id/button"
  9. android:layout_width="wrap_content"
  10. android:layout_height="wrap_content"
  11. android:text="@string/open"
  12. android:textColor="@android:color/black"
  13. android:textSize="25px" />
  14. </LinearLayout>

(2)编写WebActivity,它通过为按钮增加单击事件监听器来完成打开网页功能,其代码如下:

  1. public class WebActivity extends Activity {
  2. @Override
  3. protected void onCreate(Bundle savedInstanceState) {
  4. super.onCreate(savedInstanceState);
  5. setContentView(R.layout.main); //设置页面布局
  6. Button button = (Button) findViewById(R.id.button); //通过id值获得按钮对象
  7. button.setOnClickListener(new View.OnClickListener() {
  8. public void onClick(View v) {
  9. Intent intent = new Intent(); /创建Intent对象
  10. intent.setAction(Intent.ACTION_VIEW); //为Intent设置动作
  11. intent.setData(Uri.parse("http://www.google.com.hk")); //为Intent设置数据
  12. startActivity(intent); //将Intent传递给Activity
  13. }
  14. });
  15. }
  16. }

(3)修改AndroidManifest.xml文件,增加要启动的Activity。

(4)启动应用,其运行效果如图6.10所示。单击“打开网页”按钮,显示如图6.11所示的谷歌主页。

239-1 239-2
图6.10 打开网页界面 图6.11 谷歌主页

6.4 小 结

本章介绍的是Intent对象在Android中的作用。Intent对象用于实现不同组件之间的连接。一个Intent对象包含组件名称、动作、数据、种类、额外和标记等内容。Android系统可以根据开发人员在Intent中设置的内容选择合适的组件进行处理。在日常开发中,应该注意显式Intent和隐式Intent的应用场合。

6.5 实践与练习

  1. 编写Android程序,实现使用Intent播放视频(假设在SD卡中包含Test.m4v文件)的功能。(答案位置:光盘\TM\sl\6\6.7)

  2. 编写Android程序,实现使用Intent编辑通讯录信息(假设在通讯录中至少保存了一条记录)的功能。(答案位置:光盘\TM\sl\6\6.8)