对Android中Intent的理解

由于在Android开发中难免遇到Intent这个功能强大的东东,所以我Google了Intent的用法,在这里汇总,大部分都是摘抄各路大神的精华。

Android中提供了Intent机制来协助应用间的交互与通讯,或者采用更准确的说法是,Intent不仅可用于应用程序之间,也可用于应用程序内部的Activity/Service之间的交互。Intent这个英语单词的本意是“目的、意向”等,对于较少从事于大型平台开发工作的程序员来说,这可能是一个不太容易理解的抽象概念,因为它与我们平常使用的简单函数/方法调用,或者上节中提到的通过库调用接口的方式不太一样。在Intent的使用中你看不到直接的函数调用,相对函数调用来说,Intent是更为抽象的概念,利用Intent所实现的软件复用的粒度是Activity/Service,比函数复用更高一些,另外耦合也更为松散。

Android中与Intent相关的还有Action/Category及Intent Filter等,另外还有用于广播的Intent,这些元素掺杂在一起,导致初学者不太容易迅速掌握Intent的用法。在讲解这些名词之前,我们先来从下面的例子中感受一下Intent的一些基本用法,看看它能做些什么,之后再来思考这种机制背后的意义。

理解Intent的关键之一是理解清楚Intent的两种基本用法:一种是显式的Intent,即在构造Intent对象时就指定接收者,这种方式与普通的函数调用类似,只是复用的粒度有所差别;另一种是隐式的Intent,即Intent的发送者在构造Intent对象时,并不知道也不关心接收者是谁,这种方式与函数调用差别比较大,有利于降低发送者和接收者之间的耦合。另外Intent除了发送外,还可用于广播,这些都将在后文进行详细讲述。

下面的一小节我们来看看显式Intent的用法。

显式的Intent(Explicit Intent)

² 同一个应用程序中的Activity切换

通常一个应用程序中需要多个UI屏幕,也就需要多个Activity类,并且在这些Activity之间进行切换,这种切换就是通过Intent机制来实现的。

在同一个应用程序中切换Activity时,我们通常都知道要启动的Activity具体是哪一个,因此常用显式的Intent来实现。下面的例子用来实现一个非常简单的应用程序SimpleIntentTest,它包括两个UI屏幕也就是两个Activity——SimpleIntentTest类和TestActivity类,SimpleIntentTest类有一个按钮用来启动TestActivity,程序运行的截图如图5.3所示:

程序的代码非常简单,SimpleIntentTest类的源代码如下:

package com.tope.samples.intent.simple;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
public class SimpleIntentTest extends Activity implements View.OnClickListener{
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        Button startBtn = (Button)findViewById(R.id.start_activity);
        startBtn.setOnClickListener(this);
    }
 
    public void onClick(View v) {
        switch (v.getId()) {
        case R.id.start_activity:
            Intent intent = new Intent(this, TestActivity.class);
            startActivity(intent);
            break;
        default:
            break;
        }
    }
}

上面的代码中,主要是为“Start activity”按钮添加了OnClickListener使得按钮被点击时执行onClick()方法,onClick()方法中则利用了Intent机制,来启动TestActivity,关键的代码是下面这两行:

Intent intent = new Intent(this, TestActivity.class);
startActivity(intent);

这里定义Intent对象时所用到的是Intent的构造函数之一:

Intent(Context packageContext, Class<?> cls)

两个参数分别指定Context和Class,由于将Class设置为TestActivity.class,这样便显式的指定了TestActivity类作为Intent接收者,通过后面的startActivity()方法便可启动TestActivity。

TestActivity的代码更为简单:

package com.tope.samples.intent.simple;
import android.app.Activity;
import android.os.Bundle;
public class TestActivity extends Activity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.test_activity);
    }
}

如果我们仅仅是做上面的一些工作,还不能达到利用SimpleIntentTest启动TestActivity的目的。事实上,这样做会出现下面的Exception,导致程序退出。以下是利用logcat工具记录的log信息(省略了后半部分):

I/ActivityManager(  569): Displayed activity com.tope.samples/.SimpleIntentTest: 3018 ms
 
I/ActivityManager(  569): Starting activity: Intent { comp={com.tope.samples/com.tope.samples.TestActivity} }
 
D/AndroidRuntime(  932): Shutting down VM
 
W/dalvikvm(  932): threadid=3: thread exiting with uncaught exception (group=0x4000fe70)
 
E/AndroidRuntime(  932): Uncaught handler: thread main exiting due to uncaught exception
 
E/AndroidRuntime(  932): android.content.ActivityNotFoundException: Unable to find explicit activity class {com.tope.samples/com.tope.samples.TestActivity}; have you declared this activity in your AndroidManifest.xml?
 
E/AndroidRuntime(  932):        at android.app.Instrumentation.checkStartActivityResult(Instrumentation.java:1480)
 
E/AndroidRuntime(  932):        at android.app.Instrumentation.execStartActivity(Instrumentation.java:1454)
 
E/AndroidRuntime(  932):        at android.app.Activity.startActivityForResult(Activity.java:2656)
 
E/AndroidRuntime(  932):        at android.app.Activity.startActivity(Activity.java:2700)
 
E/AndroidRuntime(  932):        at com.tope.samples.SimpleIntentTest.onClick(SimpleIntentTest.java:24)
 
…

从这些log中我们可以看到点击按钮后startActivity的调用过程,主要的原因是:“android.content.ActivityNotFoundException: Unable to find explicit activity class {com.tope.samples/com.tope.samples.TestActivity}; have you declared this activity in your AndroidManifest.xml?”

从这些log我们可以看到原因是找不到TestActivity这个Activity,并且log中还给出了提示:你是否在AndroidManifest.xml中声明了这个Activity?解决问题的方法也就是按照提示在AndroidManifest.xml中增加TestActivity的声明,如下所示,注意粗体字部分:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
      package="com.tope.samples"
      android:versionCode="1"
      android:versionName="1.0">
    <application android:icon="@drawable/icon" android:label="@string/app_name">
        <activity android:name=".SimpleIntentTest"
                  android:label="@string/app_name">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <activity android:name=".TestActivity"/>
    </application>
    <uses-sdk android:minSdkVersion="3" />
</manifest>

完成这个修改后就一切都正常了。

从AndroidManifest.xml修改的过程我们可以体会到,Intent机制即使在程序内部且显式指定接收者,也还是需要在AndroidManifest.xml中声明TestActivity。这个过程并不像一个简单的函数调用,显式的Intent也同样经过了Android应用程序框架所提供的支持,从满足条件的Activity中进行选择,如果不在AndroidManifest.xml中进行声明,则Android应用程序框架找不到所需要的Activity。

上面的例子我们所做的是在同一应用程序中进行Activity的切换,那么在不同的应用程序中,是否也能这么做呢,答案是肯定的,不过对应的代码要稍作修改。本例中我们需要两个应用程序,可利用上例中的SimpleIntentTest作为其中之一,另外还需要写一个新的程序,来调用SimpleIntentTest应用程序中的TestActivity。

我们新建程序CrossIntentTest(注意不是新建一个类,如果是Eclipse环境,选择File->New->Project新建工程),其中只有一个Activity,其源代码与SimpleIntentTest.java类似:

package com.tope.samples.intent.cross;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
public class CrossIntentTest extends Activity
    implements View.OnClickListener{
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        Button startBtn = (Button)findViewById(R.id.start_activity);
        startBtn.setOnClickListener(this);
    }
 
    public void onClick(View v) {
        switch (v.getId()) {
        case R.id.start_activity:
            Intent intent = new Intent();
            intent.setClassName("com.tope.samples.intent.simple",
                    "com.tope.samples.intent.simple.TestActivity");
            startActivity(intent);
            break;
        default:
            break;
        }
    }
}

注意比较它与SimpleIntentTest的不同之处主要在于初始化Intent对象的过程:

Intent intent = new Intent();
intent.setClassName("com.tope.samples.intent.simple",
                    "com.tope.samples.intent.simple.TestActivity");
startActivity(intent);
小玉注释:intent.setClassName(“package的信息”,“在这个Package中所包含的Class,也就是要启动的应用程序类名”);

以上只是Intent的简单的入门,下面详细的介绍Intent的各个部分。

一、 Intent 作用
        Intent被译作意图,其实还是很能传神的,Intent期望做到的,就是把实现者和调用者完全解耦,调用者专心将以意图描述清晰,发送出去,就可以梦想成真,达到目的。
        Intent 是一个将要执行的动作的抽象的描述,一般来说是作为参数来使用,由Intent来协助完成android各个组件之间的通讯。比如说调用startActivity()来启动一个activity,或者由broadcaseIntent()来传递给所有感兴趣的BroadcaseReceiver, 再或者由startService()/bindservice()来启动一个后台的service.所以可以看出来,intent主要是用来启动其他的activity 或者service,所以可以将intent理解成activity之间的粘合剂。



二、 Intent的构成

       要在不同的activity之间传递数据,就要在intent中包含相应的东西,一般来说数据中最基本的应该包括:

-  Action: 当日常生活中,描述一个意愿或愿望的时候,总是有一个动词在其中。比如:我想 三个俯卧撑;我要 一部x片;我要 一部血泪史,之类云云。在Intent中,Action就是描述看、做、写等动作的,当你指明了一个Action,执行者就会依照这个动作的指示,接受相关输入,表现对应行为,产生符合的输出。在Intent类中,定义了一批量的动作,比如ACTION_VIEWACTION_PICK ,之类的,基本涵盖了常用动作,整一个降龙十八掌全集

 

 

标准的Activity Actions 
ACTION_MAIN                             作为一个主要的进入口,而并不期望去接受数据
ACTION_VIEW                             向用户去显示数据
ACTION_ATTACH_DATA               用于指定一些数据应该附属于一些其他的地方,例如,图片数据应该附属于联系人
ACTION_EDIT                              访问已给的数据,提供明确的可编辑
ACTION_PICK                              从数据中选择一个子项目,并返回你所选中的项目
ACTION_CHOOSER                      显示一个activity选择器,允许用户在进程之前选择他们想要的
ACTION_GET_CONTENT               允许用户选择特殊种类的数据,并返回(特殊种类的数据:照一张相片或录一段音)
ACTION_DIAL                               拨打一个指定的号码,显示一个带有号码的用户界面,允许用户去启动呼叫
ACTION_CALL                              根据指定的数据执行一次呼叫
(ACTION_CALL在应用中启动一次呼叫有缺陷,多数应用ACTION_DIAL,ACTION_CALL不能用在紧急呼叫上,紧急呼叫可以用ACTION_DIAL来实现) 
ACTION_SEND                             传递数据,被传送的数据没有指定,接收的action请求用户发数据
ACTION_SENDTO                         发送一个信息到指定的某人
ACTION_ANSWER                        处理一个打进电话呼叫
ACTION_INSERT                          插入一条空项目到已给的容器
ACTION_DELETE                          从容器中删除已给的数据
ACTION_RUN                               运行数据,无论怎么
ACTION_SYNC                             同步执行一个数据
ACTION_PICK_ACTIVITY              为已知的Intent选择一个Activity,返回别选中的类
ACTION_SEARCH                         执行一次搜索
ACTION_WEB_SEARCH                执行一次web搜索
ACTION_FACTORY_TEST              工场测试的主要进入点,


标准的广播Actions 
ACTION_TIME_TICK                   当前时间改变,每分钟都发送,不能通过组件声明来接收,只有通过Context.registerReceiver()方法来注册
ACTION_TIME_CHANGED            时间被设置
ACTION_TIMEZONE_CHANGED   时间区改变
ACTION_BOOT_COMPLETED       系统完成启动后,一次广播
ACTION_PACKAGE_ADDED         一个新应用包已经安装在设备上,数据包括包名(最新安装的包程序不能接收到这个广播)
ACTION_PACKAGE_CHANGED    一个已存在的应用程序包已经改变,包括包名
ACTION_PACKAGE_REMOVED   一个已存在的应用程序包已经从设备上移除,包括包名(正在被安装的包程序不能接收到这个广播)
ACTION_PACKAGE_RESTARTED 用户重新开始一个包,包的所有进程将被杀死,所有与其联系的运行时间状态应该被移除,包括包名(重新开始包程序不能接收到这个广播)
ACTION_PACKAGE_DATA_CLEARED 用户已经清楚一个包的数据,包括包名(清除包程序不能接收到这个广播)
ACTION_BATTERY_CHANGED 电池的充电状态、电荷级别改变,不能通过组建声明接收这个广播,只有通过Context.registerReceiver()注册
ACTION_UID_REMOVED 一个用户ID已经从系统中移除

 


-  Data(数据):  要事实的具体的数据,一般由一个Uri变量来表示

下面是一些简单的例子:

ACTION_VIEW content://contacts/1 //显示identifier为1的联系人的信息。
ACTION_DIAL  content://contacts/1 //给这个联系人打电话

除了Action和data这两个最基本的元素外,intent还包括一些其他的元素,

-  Category(范畴):  指定Action范围,这个选项指定了将要执行的这个action的其他一些额外的约束.有时通过Action,配合Data或Type,很多时候可以准确的表达出一个完整的意图了,但也会需要加一些约束在里面才能够更精准。比如,如果你虽然很喜欢做俯卧撑,但一次做三个还只是在特殊的时候才会发生,那么你可能表达说:每次吃撑了的时候 ,我都想做三个俯卧撑。吃撑了,这就对应着Intent的Category的范畴,它给所发生的意图附加一个约束。在Android中,一个实例是:所有应用的主Activity(单独启动时候,第一个运行的那个Activity...),都需要一个Category为 CATEGORY_LAUNCHER,Action为ACTION_MAIN的Intent。

 


-  Type(数据类型):   用于指定类型,以供过滤(比如ACTION_VIEW同时指定为TypeImage,则调出浏览图片的应用).一般Intent的数据类型能够根据数据本身进行判定,但是通过设置这个属性,可以强制采用显式指定的类型而不再进行判定。

-  Component(组件):   当我们常用Action,Data/Type,Category去描述一个意图,这是Android推荐,这种模式称:Implicit Intents. 通过这种模式,提供一种灵活可扩展的模式,给用户和第三方应用一个选择权。比如:一个邮箱软件,大部分功能都好,就是选择图片的功能做的很土,怎么办?如果它采用的是Implicit Intents,那么它就是一个开放的体系了,手机中没有其他图片选择功能的情况下,可以继续使用邮箱默认的,如果有,你可以任意选择来替代原有模块完成这功能,一切都自然而然。但这种模式需要付出性能上的开销,因为毕竟有一个检索过程。于是,Android提供了另一种模式,叫做Explicit Intents ,就需要Component的帮助了。Component就是完整的类名,形如com.xxxxx.xxxx ,一旦指明了,可以直接调用,自然是速度快. 适合在你明确知道这就是一个内部模块的时候,使用它。


-  Extras(附加信息):    是其它所有附加信息的集合。使用extras可以为组件提供扩展信息,比如,如果要执行“发送电子邮件”这个动作,可以将电子邮件的标题、正文等保存在extras里,传给电子邮件发送组件。


-  Flags(标志位):   能识别,有输入,整个Intent基本就完整了,但还有一些附件的指令,需要放在Flags中带过去。顾名思义,Flags是一个整形数,有一些列的标志 位构成,这些标志,是用来指明运行模式的。比如,你期望这个意图的执行者,和你运行在两个完全不同的任务中(或说进程也无妨吧...),就需要设置FLAG_ACTIVITY_NEW_TASK 的标志位。


Android 的一个特色就是 application A 的 activity 可以启动 application B 的 activity,尽管 A 和 B 是毫无干系的,而在用户看来,两个场景紧密联系,视觉上二者构成了一个整体。Android 就是把这种误觉定义为 Task,它既不是 class,也不是 AndroidMainifest.xml 中的一个元素。从表现上看 Task 就像是一个 stack,一个一个的 activity 是构成 stack 的元素,做着入栈 (push) 和出栈 (pop-up)这样简单重复性的劳动。

默认的规则总是满足大多数的应用场景,但是也总会有一些例外打破习以为常的惯例。Task 的默认规则同样并非牢不可破,修改的方法还是有的。借助 Intent 中的 flag 和 AndroidMainifest.xml 中 activity 元素的属性,就可以控制到 Task 里 Activity 的关联关系和行为。

在 android.content.Intent 中一共定义了20种不同的 flag,其中和 Task 紧密关联的有四种:

FLAG_ACTIVITY_NEW_TASK
FLAG_ACTIVITY_CLEAR_TOP
FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
FLAG_ACTIVITY_SINGLE_TOP
在使用这四个 flag 时,一个 Intent 可以设置一个 flag,也可以选择若干个进行组合。

默认情况下,通过 startActivity() 启动一个新的 Activity,新的 Activity 将会和调用者在同一个 stack 中。但是,如果在传递给 startActivity() 的 Intent 对象里包含了 FLAG_ACTION_NEW_TASK,情况将发生变化,系统将为新的 Activity “寻找”一个不同于调用者的 Task。不过要找的Task 是不是一定就是 NEW 呢?如果是第一次执行,则这个设想成立,如果说不是,也就是说已经有一个包含此 Activity 的Task 存在,则不会再启动 Activity。

如果 flag 是 FLAG_ACTIVITY_CLEAR_TOP,同时当前的 Task 里已经有了这个 Activity,那么情形又将不一样。Android 不但不会启动新的 Activity 实例,而且还会将 Task 里 该 Activity 之上的所有 Activity 一律结束掉,然后将 Intent 发给这个已存在的 Activity。Activity 收到 Intent 之后,可以在 onNewIntent() 里做下一步的处理,也可以自行结束然后重新创建自己。如果 Activity 在 AndroidMainifest.xml 里将启动模式设置成multiple,– 默认模式,并且 Intent 里也没有设置 FLAG_ACTIVITY_SINGLE_TOP,那么它将选择后者。否则,它将选择前者。FLAG_ACTIVITY_CLEAR_TOP 还可以和 FLAG_ACTION_NEW_TASK 配合使用。

如果 flag 设置的是 FLAG_ACTIVITY_SINGLE_TOP,则意味着如果 Activity 已经是运行在 Task 的 top,则该 Activity 将不会再被启动。


三、 intent的解析

在应用中,我们可以以两种形式来使用Intent:

-          直接Intent:指定了component属性的Intent(调用setComponent(ComponentName)或者setClass(Context, Class)来指定)。通过指定具体的组件类,通知应用启动对应的组件。

-          间接Intent:没有指定comonent属性的Intent。这些Intent需要包含足够的信息,这样系统才能根据这些信息,在在所有的可用组件中,确定满足此Intent的组件。

         对于直接Intent,Android不需要去做解析,因为目标组件已经很明确,Android需要解析的是那些间接Intent,通过解析,将 Intent映射给可以处理此Intent的Activity、IntentReceiver或Service。

Intent解析机制主要是通过查找已注册在AndroidManifest.xml中的所有<intent-filter>及其中定义的Intent,通过PackageManager(注:PackageManager能够得到当前设备上所安装的application package的信息) 来查找能过处理这个Intent的component。在这个解析过程中,Android是通过Intent的action、type、category这三个属性来进行判断的,判断方 法如下:

-          如果Intent指明定了action,则目标组件的IntentFilter的action列表中就必须包含有这个action,否则不能匹配;

-          如果Intent没有提供type,系统将从data中得到数据类型。和action一样,目标组件的数据类型列表中必须包含Intent的数据类型,否则不能匹配。

-          如果Intent中的数据不是content: 类型的URI,而且Intent也没有明确指定它的type,将根据Intent中数据的scheme (比如 http: 或者 mailto: ) 进行匹配。同上,Intent 的scheme必须出现在目标组件的scheme列表中。

-          如果Intent指定了一个或多个category,这些类别必须全部出现在组建的类别列表中。比如Intent中包含了两个类别:LAUNCHER_CATEGORY 和 ALTERNATIVE_CATEGORY,解析得到的目标组件必须至少包含这两个类别。


下面,以Android SDK中的便笺例子来说明,Intent如何定义及如何被解析。这个应用可以让用户浏览便笺列表、查看每一个便笺的详细信息。

Manifest.xml

Xml代码   收藏代码
  1. <manifest xmlns:android="http://schemas.android.com/apk/res/android"   
  2. package="com.google.android.notepad">   
  3.     <application android:icon="@drawable/app_notes"   
  4. android:label="@string/app_name">   
  5.     <provider class="NotePadProvider"   
  6. android:authorities="com.google.provider.NotePad" />   
  7.     <activity class=".NotesList"="@string/title_notes_list">   
  8.       <intent-filter>   
  9.         <action android:value="android.intent.action.MAIN"/>   
  10.         <category android:value="android.intent.category.LAUNCHER" />   
  11.       </intent-filter>   
  12.       <intent-filter>   
  13.         <action android:value="android.intent.action.VIEW"/>   
  14.         <action android:value="android.intent.action.EDIT"/>   
  15.         <action android:value="android.intent.action.PICK"/>   
  16.         <category android:value="android.intent.category.DEFAULT" />   
  17.         <type android:value="vnd.android.cursor.dir/vnd.google.note" />   
  18.       </intent-filter>   
  19.       <intent-filter>   
  20.         <action android:value="android.intent.action.GET_CONTENT" />   
  21.         <category android:value="android.intent.category.DEFAULT" />   
  22.         <type android:value="vnd.android.cursor.item/vnd.google.note" />   
  23.       </intent-filter>   
  24.     </activity>   
  25.     <activity class=".NoteEditor"="@string/title_note">   
  26.       <intent-filter android:label="@string/resolve_edit">   
  27.         <action android:value="android.intent.action.VIEW"/>   
  28.         <action android:value="android.intent.action.EDIT"/>   
  29.         <category android:value="android.intent.category.DEFAULT" />   
  30.         <type android:value="vnd.android.cursor.item/vnd.google.note" />   
  31.       </intent-filter>   
  32.       <intent-filter>   
  33.         <action android:value="android.intent.action.INSERT"/>   
  34.         <category android:value="android.intent.category.DEFAULT" />   
  35.         <type android:value="vnd.android.cursor.dir/vnd.google.note" />   
  36.       </intent-filter>   
  37.     </activity>   
  38.     <activity class=".TitleEditor"="@string/title_edit_title"   
  39. android:theme="@android:style/Theme.Dialog">   
  40.       <intent-filter android:label="@string/resolve_title">   
  41.         <action android:value="com.google.android.notepad.action.EDIT_TITLE"/>   
  42.         <category android:value="android.intent.category.DEFAULT" />   
  43.         <category android:value="android.intent.category.ALTERNATIVE" />   
  44.         <category android:value="android.intent.category.SELECTED_ALTERNATIVE"/>   
  45.         <type android:value="vnd.android.cursor.item/vnd.google.note" />   
  46.       </intent-filter>   
  47.     </activity>   
  48. </application>   
  49. </manifest>  

 

例子中的第一个Activity 是com.google.android.notepad.NotesList,它是应用的主入口,提供了三个功能,分别由三个 intent-filter进行描述:
        1、第一个是进入便笺应用的顶级入口(action为android.app.action.MAIN)。类型为android.app.category.LAUNCHER表明这个Activity将在Launcher中列出。
        2、第二个是,当type为vnd.android.cursor.dir/vnd.google.note(保存便笺记录的目录) 时,可以查看可用的便笺(action为android.app.action.VIEW),或者让用户选择一个便笺并返回给调用者(action为 android.app.action.PICK)。
        3、第三个是,当type为vnd.android.cursor.item/vnd.google.note时,返回给调用者一个用户选择的便笺(action为android.app.action.GET_CONTENT),而用户却不需要知道便笺从哪里读取的。 有了这些功能,下面的Intent就会被解析到NotesList这个activity:

    * { action=android.app.action.MAIN }:与此Intent匹配的Activity,将会被当作进入应用的顶级入口。 

    * { action=android.app.action.MAIN, category=android.app.category.LAUNCHER }:这是目前Launcher实际使用的 Intent,用于生成Launcher的顶级列表。 

    * { action=android.app.action.VIEW data=content://com.google.provider.NotePad/notes }:显示"content://com.google.provider.NotePad/notes"下的所有便笺的列表,使用者可以遍历列表,并且察看某便笺的详细信息。 

    * { action=android.app.action.PICK data=content://com.google.provider.NotePad/notes }:显示"content://com.google.provider.NotePad/notes"下的便笺列表,让用户可以在列表中选择一个,然后将选择的便笺的 URL返回给调用者。 

    * { action=android.app.action.GET_CONTENT type=vnd.android.cursor.item/vnd.google.note }:和 上面的action为pick的Intent类似,不同的是这个Intent允许调用者(在这里指要调用NotesList的某个Activity)指定 它们需要返回的数据类型,系统会根据这个数据类型查找合适的 Activity(在这里系统会找到NotesList这个Activity),供用户选择便笺。 


        第二个Activity是com.google.android.notepad.NoteEditor,它为用户显示一条便笺,并且允许 用户修改这个便笺。它定义了两个intent-filter,所以具有两个功能。第一个功能是,当数据类型为 vnd.android.cursor.item/vnd.google.note时,允许用户查看和修改一个便签(action为 android.app.action.VIEW和android.app.action.EDIT)。第二个功能是,当数据类型为 vnd.android.cursor.dir/vnd.google.note,为调用者显示一个新建便笺的界面,并将新建的便笺插 入到便笺列表中(action为android.app.action.INSERT)。

      有了这两个功能,下面的Intent就会被解析到NoteEditor这个activity:

    * { action=android.app.action.VIEW data=content://com.google.provider.NotePad/notes/{ID} } :向用户显示标识为 ID的便笺。

    * { action=android.app.action.EDIT data=content://com.google.provider.NotePad/notes/{ID} }:允许用户编辑标识为ID的便笺。 

    * { action=android.app.action.INSERT data=content://com.google.provider.NotePad/notes }:在“content://com.google.provider.NotePad/notes”这个便笺列表中创建一个新的空便笺,并允许用 户编辑这个便签。当用户保存这个便笺后,这个新便笺的URI将会返回给调用者。 


        最后一个Activity是com.google.android.notepad.TitleEditor,它允许用户编辑便笺的标题。它可以被实现为 一个应用可以直接调用(在Intent中明确设置component属性)的类,不过这里我们将为你提供一个在现有的数据上发布可选操作的方法。在这个 Activity的唯一的intent-filter中,拥有一个私有的action: com.google.android.notepad.action.EDIT_TITLE,表明允许用户编辑便笺的标题。和前面的view和edit 动作一样,调用这个Intent 的时候,也必须指定具体的便笺(type为vnd.android.cursor.item/vnd.google.note)。不同的是,这里显示和编 辑的只是便笺数据中的标题。
      除了支持缺省类别(android.intent.category.DEFAULT),标题编辑器还支持另外两个标准类别: android.intent.category.ALTERNATIVE和 android.intent.category.SELECTED_ALTERNATIVE。实现了这两个类别之后,其它 Activity就可以调用queryIntentActivityOptions(ComponentName, Intent[], Intent, int)查询这个Activity提供的action,而不需要了解它的具体实现;或者调用addIntentOptions(int, int, ComponentName, Intent[], Intent, int, Menu.Item[])建立动态菜单。需要说明的是,在这个intent-filter中有一个明确的名称(通过android:label= "@string/resolve_title"指定),在用户浏览数据的时候,如果这个Activity是数据的一个可选操作,指定明确的名称可以为用 户提供一个更好控制界面。
      有了这个功能,下面的Intent就会被解析到TitleEditor这个Activity:

    * { action=com.google.android.notepad.action.EDIT_TITLE data=content://com.google.provider.NotePad/notes/{ID} }:显示并且允许用户编辑标识为ID的便笺的标题。


最后再补充上Intent的一些例子:

如果是从BroadcastReceiver 启动一个新的Activity , 不要忘记i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 
 

public class MyReceiver extends BroadcastReceiver{

public static final String action="acc";
 public void onReceive(Context context, Intent intent) {
  Intent i=new Intent(context,Receivered.class);
  i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
  context.startActivity(i);
 }


}

1. 指定act ion 和type 
// SIM import
        Intent importIntent = new Intent(Intent.ACTION_VIEW);
        importIntent.setType("vnd.android.cursor.item/sim-contact");
        importIntent.setClassName("com.android.phone", "com.android.phone.SimContacts");
        menu.add(0, 0, 0, R.string.importFromSim)
                .setIcon(R.drawable.ic_menu_import_contact)
                .setIntent(importIntent);
                
2. 指定act ion, da ta和type 
(1)隐式查找type
示例代码:
uri: content://simcontacts/simPeople/(id)
intent = new Intent("android.intent.action.SIMEDIT",uri);
            startActivity(intent);

程序会很据data中的uri去查找匹配的type(必须的)            
provider中的getType()            
case SIM_PEOPLE_ID:
            return "vnd.android.cursor.item/sim-contact"; 

配置文件中的filter设定           
AndroidManifest.xml
    <intent-filter>
                <action android:name="android.intent.action.SIMEDIT" />
                <category android:name="android.intent.category.DEFAULT" />          
                <data android:mimeType="vnd.android.cursor.item/sim-contact" />
      </intent-filter>

也可以自己设定type,但只能使用 setDataAndType()     
      
3. 其他设定intent的属性方式 
   Intent setComponent(ComponentName component) 
   Intent setClassName(Context packageContext, String className)
   Intent setClassName(String packageName, String className)
   Intent setClass(Context packageContext, Class<?> cls)
  


Intent 应该算是Android中特有的东西。你可以在Intent中指定程序 要执行的动作(比如:view,edit,dial),以及程序执行到该动作时所需要的资料 。都指定好后,只要调用startActivity(),Android系统 会自动寻找最符合你指定要求的应用 程序,并执行该程序。

下面列出几种Intent 的用法
显示网页:

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

Uri uri = Uri.parse("geo:38.899533,-77.036476"); 
Intent it = new Intent(Intent.Action_VIEW,uri); 
startActivity(it); 
路径规划:

Uri uri = Uri.parse("http://maps.google.com/maps?f=dsaddr=startLat%20startLng&daddr=endLat%20endLng&hl=en"); 
Intent it = new Intent(Intent.ACTION_VIEW,URI); 
startActivity(it); 
拨打电话:
调用拨号程序

Uri uri = Uri.parse("tel:xxxxxx"); 
Intent it = new Intent(Intent.ACTION_DIAL, uri);   
startActivity(it);   
Uri uri = Uri.parse("tel.xxxxxx"); 
Intent it =new Intent(Intent.ACTION_CALL,uri); 
要使用这个必须在配置文件 中加入<uses-permission id="android .permission.CALL_PHONE" /> 
发送SMS/MMS
调用发送短信 的程序

Intent it = new Intent(Intent.ACTION_VIEW);    
it.putExtra("sms_body", "The SMS text");    
it.setType("vnd.android-dir/mms-sms");    
startActivity(it);   
发送短信

Uri uri = Uri.parse("smsto:0800000123");    
Intent it = new Intent(Intent.ACTION_SENDTO, uri);    
it.putExtra("sms_body", "The SMS text");    
startActivity(it);   
发送彩信

Uri uri = Uri.parse("content://media/external/images/media/23");    
Intent it = new Intent(Intent.ACTION_SEND);    
it.putExtra("sms_body", "some text");    
it.putExtra(Intent.EXTRA_STREAM, uri);    
it.setType("image/png");    
startActivity(it); 
发送Email


Uri uri = Uri.parse("mailto:xxx@abc.com"); 
Intent it = new Intent(Intent.ACTION_SENDTO, uri); 
startActivity(it); 
Intent it = new Intent(Intent.ACTION_SEND);    
it.putExtra(Intent.EXTRA_EMAIL, "me@abc.com");    
it.putExtra(Intent.EXTRA_TEXT, "The email body text");    
it.setType("text/plain");    
startActivity(Intent.createChooser(it, "Choose Email Client"));   
Intent it=new Intent(Intent.ACTION_SEND);      
String[] tos={"me@abc.com"};      
String[] ccs={"you@abc.com"};      
it.putExtra(Intent.EXTRA_EMAIL, tos);      
it.putExtra(Intent.EXTRA_CC, ccs);      
it.putExtra(Intent.EXTRA_TEXT, "The email body text");      
it.putExtra(Intent.EXTRA_SUBJECT, "The email subject text");      
it.setType("message/rfc822");      
startActivity(Intent.createChooser(it, "Choose Email Client"));    
添加附件

Intent it = new Intent(Intent.ACTION_SEND);    
it.putExtra(Intent.EXTRA_SUBJECT, "The email subject text");    
it.putExtra(Intent.EXTRA_STREAM, "file:///sdcard/mysong.mp3");    
sendIntent.setType("audio/mp3");    
startActivity(Intent.createChooser(it, "Choose Email Client")); 
播放 多媒体

   
Intent it = new Intent(Intent.ACTION_VIEW); 
Uri uri = Uri.parse("file:///sdcard/song.mp3"); 
it.setDataAndType(uri, "audio/mp3"); 
startActivity(it); 
Uri uri = Uri.withAppendedPath(MediaStore.Audio.Media.INTERNAL_CONTENT_URI, "1");    
Intent it = new Intent(Intent.ACTION_VIEW, uri);    
startActivity(it);   
Uninstall 程序

Uri uri = Uri.fromParts("package", strPackageName, null);    
Intent it = new Intent(Intent.ACTION_DELETE, uri);    
startActivity(it);

uninstall apk 
Uri uninstallUri = Uri.fromParts("package", "xxx", null);

returnIt = new Intent(Intent.ACTION_DELETE, uninstallUri); 
install apk 
Uri installUri = Uri.fromParts("package", "xxx", null);

returnIt = new Intent(Intent.ACTION_PACKAGE_ADDED, installUri); 
play audio 
Uri playUri = Uri.parse("file:///sdcard/download/everything.mp3");

returnIt = new Intent(Intent.ACTION_VIEW, playUri); 
//发送附件 
Intent it = new Intent(Intent.ACTION_SEND);   
it.putExtra(Intent.EXTRA_SUBJECT, "The email subject text");   
it.putExtra(Intent.EXTRA_STREAM, "file:///sdcard/eoe.mp3");   
sendIntent.setType("audio/mp3");   
startActivity(Intent.createChooser(it, "Choose Email Client")); 
//搜索应用 
Uri uri = Uri.parse("market://search?q=pname:pkg_name");   
Intent it = new Intent(Intent.ACTION_VIEW, uri);   
startActivity(it);   
//where pkg_name is the full package path for an application  

//显示指定应用的详细页面(这个好像不支持了,找不到app_id) 
Uri uri = Uri.parse("market://details?id=app_id");   
Intent it = new Intent(Intent.ACTION_VIEW, uri);   
startActivity(it);   
//where app_id is the application ID, find the ID   
//by clicking on your application on Market home   
//page, and notice the ID from the address bar



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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值