在android中,intent就像是一个邮差,辛勤高效的在各个组件之间来回穿梭。我们可以通过它启动一个Activity或者Service,或者是发送给广播组件,又或者是与后台的Service进行通信。所谓的Intent,字面意思就是"意图,目的",在android中的定义就是一个动作的抽象描述,类似于接口是抽象的行为协议一样,但这两者在实现上是不同的东西。

即使是好的邮差,如果没有邮递地址,依然无法正确的将货物送到指定的地方。这个完全交给系统来处理,它会帮Intent寻找合适的邮递地址,像是发送给Activity的Intent就会准确的发送给该Activity,发送个各个广播的Intent就会发送给指定的广播,从不会出错。

一.Intent的组成

Intent所包含的信息主要包括两个方面:action和data。

action就是所要执行的动作,像是我们经常在根文件中声明的Activity的动作:ACTION_MAIN,表示应用程序的入口。action通常是一个大写表示的字符串,用来简要的描述动作,当然,我们也可以自定义自己应用的Intent,不过在使用的时候必须指定全称,也就是包名。

正如方法签名包含了参数和返回值一样,action的名字也必须尽量包含了该action的信息,所以在自定义自己的action的时候,名字是非常重要的,必须尽可能的与其他的action区分开来,而且还要将该名字与intent的其他部分紧密的结合在一起,简而言之,不是单独的定义action,而是要定义其他组件能够处理的完整协议。

我们可以通过setAction()来设置action和通过getAction()来获取action。

一般的action像是这样:

public static final String ACTION_DIAL = "android.intent.action.DIAL"

data是我们的动作所要操作的数据,通常是以Uri的形式表示。data并不是单独的出现,它们经常和action成对出现,像是这样:ACTION_VIEW content://contacts/people/1,就是用于展现手机中通讯录标识为1的人的信息,而且还提示了数据的存放地点是在设备上,并且是由content provider所控制。

当一个Intent被发送给适合的组件时,我们除了要知道data的Uri之外,还必须知道数据的类型,也就是MIME type。我们可以显式地指明data的Uri和MIME type,可以通过setData()指明数据的uri,setType()指明数据的MIME type,setDataAndType()指明数据的Uri和MIME type,getData()用于获取Uri,而getType()用于获取type。

除了上面的主要属性外,Intent还可以包含其他信息:category,type,component和extras。

category给出了action执行的其他信息,像是CATEGORY_LAUNCHER表示目标Activity是应用程序中最优先被执行的Activity,也就是所谓的top-level Activity。还有CATEGORY_HOME,表示的就是手机开机启动后或者按下HOME键后显示的Activity,CATEGORY_BROWSABLE表示的就是能通过在网页浏览器中点击链接而激活的Activity,而CATEGORY_PREFERENCE表示Activity是用于设置的Activity。

type是显式的指明data的MIME type,一旦指明了type,就只能使用该类型的data。

component是显式的指明了使用Intent的组件,这时其他属性的设置就是可选的,因为它们的设置都是为了方便寻找合适的组件。

extras正如字面意思,就是额外的信息,它们使用Bundle类型进行数据传递,也就是键值对,像是time-zone代表的就是新的时间区域。通常它代表的是Intent的扩展信息,像是我们的action如果能够发送邮件,那么我们可以将邮件的标题和内容放在extras里面。

像是这样:

Bundle bundle = new Bundle();
intent.putExtras(bundle);

flags的作用像是告诉系统应该如何启动Activity,或者在启动后应该如何处理该Activity等。

二.Intent的使用

Intent可以分为两类:显式的Intent和隐式的Intent。

显式的Intent指定了使用Intent的组件,所以它并不需要其他信息。通常它使用在应用程序的内部,像是启动应用程序的其他Activity或者内部定义的Service。

隐式的Intent并没有指定组件,所以它需要更加详细的信息以确保系统能够发送给正确的组件。但是这些还是不够的,组件本身还是要提供信息来确保它接收到正确的Intent,这就是intent-filter的作用。我们经常在根文件中注册一个组件的时候,指明它的intent-filter,像是在程序中使用广播组件的时候,我们可以显式的指明intent-filter,像是这样:registerReceiver(BroadcastReceiver, IntentFilter)。

我们在声明intent-filter的时候,通常只需要指定三个属性:action,data和category,但是一般情况下我们有时候也不会完整的设定这三个属性,像是只设定action和category,那么这时的filter就只会匹配没有data的intent。在intent-filter中的data还进一步划分成几个属性:type,scheme,authority和path。type就是我们熟悉的MIME type,我们简单的讲解一下其他我们不熟悉的属性。

所谓的sheme就是我们上面讲的content:Uri等信息,值得注意的是,如果我们只是声明了scheme而没有声明type的话,那么filter就只会匹配没有type的Intent,而像是content:Uri是不会被匹配的,因为content provider在存储的时候是有保存MIME type的信息,所以如果没有提供type的话,是无法从里面提取出data。如果我们只提供type而没有提供scheme的话,那就表示匹配没有Uri或者包含content:Uri和file:Uri的Intent。如果scheme和type都没有,那么匹配的将会是没有data或者type的Intent。值得注意的是,当我们需要指定authority的时候,authority的scheme列表和我们的intent-filter的scheme列表必须相同,而path则需要包括authority和scheme列表。

我们来一个例子:

content://com.example.project:200/folder/subfolder/etc

其中,content就是scheme,com.example.project就是host,而200是port,path就是folder/subfolder/etc,host和port加起来就是URI authority,但注意,如果host没有指定,那么port也是没有必要的。

以上介绍的属性都是可选的,但这并不意味着它们是独立的:如果想要声明一个authority,那么scheme就是必要的。如果想要声明一个path,scheme和authority都是必要的。

我们再来看一个例子:

<intent-filter>
<data android:mimeType="audio/mpeg"/>
</intent-filter>

这里我们可以使用audio/*,这就表示audio的所有子类型都可以匹配。

像是这样:

<data android:scheme="http" android:type="video/*"/>

表示我们的数据类型是video,然后可以通过网络来获取。

在实际的应用中,我们使用隐式的Intent比较多,之所以使用隐式的Intent,是因为我们想要让系统来决定哪个组件是最适合该Intent的,通常系统会比人更加清楚什么才是最适合的,只要我们给出的信息足够详细。

最好的情况就是我们在注册一个组件的时候,如果希望它接收Intent,那么就必须在根文件中声明它的intent-filter,这样无论是显式的还是隐式的Intent它都能接收到,如果没有,那么它只会接收显式的Intent。

IntentFilter并不像它的名字一样,具有过滤保护的作用,因为它无法阻止显式的Intent发送给组件,它只能阻止隐式的Intent发送给该组件。

一个intent-filter可以包含多个action:

<intent-filter>
<action android:name="android.intent.action.VIEW"/>
<action android:name="android.intent.action.EDIT"/>
<action android:name="android.intent.action.PICK"/>
<category android:name="android.intent.category.DEFAULT"/>
<data android:mimeType="vnd.android.cursor.dir/vnd.google.note"/>
</intent-filter>

这个filter声明了很多action,它允许用户view或者edit目录,也允许从目录中pick一个note出来。
      值得注意的是,filter声明了DEFAULT这个category。之所以声明为DEFAULT,是因为Context.startActivity()和Activity.startActivityForResult()这两个方法都默认Intent包含DEFAULT这个category,除了两个例外情况:显式的声明目标activity的名字和包含action-MAIN和category-LAUNCHER的Intent。

这里还有一个特别的东西:data的mimeType。我们看到,这里的的mimeType声明为vnd.android.cursor.dir/vnd.google.note,说明我们可以从Content Provider中获取Cursor并进一步获取Note Pad的数据。

最后发送给Activity的Intent大概像是这样子:

{action:android.intent.action.VIEW data:content://com.google.provider.NotePad/notes}

{action:android.intent.action.PICK data:content://com.google.provider.NotePad/notes}

{action:android.intent.action.EDIT data:content://com.google.provider.NotePad/notes}

当然,这里的Intent并不是完整的,还得考虑一下Activity的情况。如果该Activity用于展示所有的数据,Intent就是上面这样子, 但如果只是单独作用于一条数据的Activity,就算intent-filter是一样的,实际上的Intent应该像是这样子:

{action:android.intent.action.VIEW data:content://com.google.provider.NotePad/notes/ID}

再来看一个例子:

<intent-filter android:label="@string/resolve_title">
<action android:name="com.android.notepad.action.EDIT_TITLE"/>
<category android:name="android.intent.category.DEFAULT"/>
<category android:name="android.intent.category.ALTERNATIVE"/>
<category android:name="android.intent.category.SELECTED_ALTERNATIVE"/>
<data android:mimeType="vnd.android.cursor.item/vnd.google.note"/>
</intent-filter>

这个Filter声明的action是修改title。为了能够支持DEFAULT这个category,我们还必须支持其他两个标准的categories:ALTERNATIVE和SELECTED_ALTERNATIVE。这个Intent大概就是这样子:
      {action:com.android.notepad.action.EDIT_TITLE data:content://com.google.provider.NotePad/notes/ID}

android系统本身就定义了大量的标准action和category,如果有需要的话,可以自己查阅官方文档。

接下来我们就针对常见的使用场景来分析如何使用Intent。

1.Activity的跳转:

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

关于Activity的跳转,还有一个知识点需要补充。我们知道,在android中有一个Task(栈),专门用于存放Activity,它遵循的是"先进后出"的原则,但如果我们不想要遵循这个原则,想要取出指定的Activity,我们就可以利用一个东西:Flag,也就是上面提到的Flag:

Intent intent = new Intent(Activity1.this, Activity2.class);
//如果Activity在Task中存在,并且是在最顶端,不会启动新的Activity
intent.addFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT); //如果Activity在Task中存在,将Activity上面的所有Activity结束掉
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); //默认的跳转类型。将Activity放到一个新的Task中
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); //如果Activity已经运行到Task,再次跳转不会再运行这个Activity
intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);

2.向另一个Activity传递数据:

Intent intent = new Intent(Activity1.this, Activity2.class);
Bundle bundle = new Bundle();
bundle.putString("name", "Jack");
intent.putExtras(bundle);
startActivity(intent);

至于接收数据:

Bundle bundle = new Bundle();
String name = bundle.getString("name");

3.向上一个Activity返回结果,这种情况针对的是startActivityForResult(intent, requestCode)启动的Activity:

Intent intent = getIntent();
Bundle bundle = new Bundle();
bundle.putString("name", "Jack");
intent.putExtras(bundle);
setResult(RESULT_OK, intent);

4.回调上一个Activity的结果处理函数:

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data){
super.onActivityResult(requestCode, resultCode, data);
if(requestCode == REQUEST_CODE){
if(resultCode == RESULT_OK){
String temp = null;
Bundle bundle = data.getExtras();
....
}
}
}

接下来就是一些调用官方应用程序的使用场景:
1.显示网页:

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

2.显示地图:

Uri uri = Uri.parse("geo:38.899533,-77.036476");
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
startActivity(intent);

3.路径规划:

Uri uri = Uri.parse("http://maps.google.com/maps?f=d&saddr=startLat%20startLng&daddr=endLat%20endLng&hl=en");
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
startActivity(intent);

4.打电话:
(1)叫出拨号程序:

Uri uri = Uri.parse("tel:0800000123");
Intent intent = new Intent(Intent.ACTION_DIAL, uri);

(2)直接打电话:

Uri uri = Uri.parse("tel:0800000123");
Intent intent = new Intent(Intent.ACTION_CALL, uri);
startActivity(intent);

这些都要在根文件中声明权限:<user-permission id="android.permission.CALL_PHONE"/>
5.发送SMS(短信)和MMS(彩信):

//调用短信程序
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
intent.putExtra("content", "你好");
it.setType("vnd.android-dir/mms-sms");
startActivity(intent);
//发送短信
Uri uri = Uri.parse("smsto://0800000123");
Intent intent = new Intent(Intent.ACTION_SENDTO, uri);
intent.putExtra("content", "你好");
startActivity(intent);
//发送彩信
Uri uri = Uri.parse("content://media/external/images/media/23");
Intent intent = new Intent(Intent.ACTION_SEND);
intent.putExtra("content", "。。。");
intent.putExtra(Intent.EXTRA_STREAM, uri);
intent.setType("image/png");
startActivity(intent);

6.发送Email:

Uri uri = Uri.parse("mailto:xxx@abc.com");
Intent intent = new Intent(Intent.ACTION_SENDTO, uri);
startActivity(intent); Intent intent = new Intent(Intent.ACTION_SEND);
intent.putExtra(Intent.EXTRA_EMAIL, "me@abc.com");
intent.putExtra(Intent.EXTRA_TEXT, "The email body text");
intent.setType("text/plain");
startActivity(Intent.createChooser(intent, "Choose Email Client")); Intent intent=new Intent(Intent.ACTION_SEND);
String[] tos={"me@abc.com"};
String[] ccs={"you@abc.com"};
intent.putExtra(Intent.EXTRA_EMAIL, tos);
intent.putExtra(Intent.EXTRA_CC, ccs);
intent.putExtra(Intent.EXTRA_TEXT, "The email body text");
intent.putExtra(Intent.EXTRA_SUBJECT, "The email subject text");
intent.setType("message/rfc822");
startActivity(Intent.createChooser(intent, "Choose Email Client")); //传送附件
Intent intent = new Intent(Intent.ACTION_SEND);
intent.putExtra(Intent.EXTRA_SUBJECT, "The email subject text");
intent.putExtra(Intent.EXTRA_STREAM, "file:///sdcard/mysong.mp3"); sendIntent.setType("audio/mp3");
startActivity(Intent.createChooser(intent, "Choose Email Client"));

7.播放多媒体:

Uri uri = Uri.parse("file:///sdcard/song.mp3");
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
intent.setType("audio/mp3");
startActivity(intent); Uri uri = Uri.withAppendedPath(MediaStore.Audio.Media.INTERNAL_CONTENT_URI, "1");
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
startActivity(intent);

8.Market相关:

//寻找某个应用
Uri uri = Uri.parse("market://search?q=pname:pkg_name");
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
startActivity(intent); //显示某个应用的相关信息
Uri uri = Uri.parse("market://details?id=app_id");
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
startActivity(intent);

9.Uninstall应用程序:

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

Intent----android中的伟大邮差的更多相关文章

  1. (转)Android 中LocalBroadcastManager的使用方式

    发表于2个月前(2014-11-03 22:05)   阅读(37) | 评论(0) 0人收藏此文章, 我要收藏 赞0 1月10日 #长沙# OSC 源创会第32期开始报名 摘要 android中广播 ...

  2. Android中Intent的用法总结

    Intent只在Android中特有,我把它比作一种运载工具,就像飞机一样,会把一些人带到某个地方,而且如果需要的话,还可以找到机上有哪些人员(数据),这就需要另外一些设备来支持(如:Bundle), ...

  3. Android中如何使用Intent在Activity之间传递对象[使用Serializable或者Parcelable]

    http://blog.csdn.net/cjjky/article/details/6441104 在Android中的不同Activity之间传递对象,我们可以考虑采用Bundle.putSeri ...

  4. Android中Intent传递对象的两种方法(Serializable,Parcelable)

    今天要给大家讲一下Android中 Intent中如何传递对象,就我目前所知道的有两种方法,一种是Bundle.putSerializable(Key,Object);另一种是 Bundle.putP ...

  5. Android中Intent传值与Bundle传值的区别详解

    Android中Intent传值与Bundle传值的区别详解 举个例子我现在要从A界面跳转到B界面或者C界面   这样的话 我就需要写2个Intent如果你还要涉及的传值的话 你的Intent就要写两 ...

  6. Android中的Intent Filter匹配规则介绍

    本文主要介绍了隐式Intent匹配目标组件的规则,若有叙述不清晰或是不准确的地方希望大家指出,谢谢大家: ) 1. Intent简介 Intent用于在一个组件(Component,如Activity ...

  7. Android中的Intent详解

    前言: 每个应用程序都有若干个Activity组成,每一个Activity都是一个应用程序与用户进行交互的窗口,呈现不同的交互界面.因为每一个Acticity的任务不一样,所以经常互在各个Activi ...

  8. Android中Intent组件详解

    Intent是不同组件之间相互通讯的纽带,封装了不同组件之间通讯的条件.Intent本身是定义为一个类别(Class),一个Intent对象表达一个目的(Goal)或期望(Expectation),叙 ...

  9. android中使用Intent在activity之间传递数据

    android中intent传递数据的简单使用: 1.使用intent传递数据: 首先将需要传递的数据放入到intent中 Intent intent = new Intent(MainActivit ...

  10. 【转】Android中intent传递对象和Bundle的用法

    原文网址:http://blog.csdn.net/lixiang0522/article/details/8642202 android中的组件间传递的对象一般实现Parcelable接口,当然也可 ...

随机推荐

  1. 单元测试Mockito中的Mock和Spy

    转载:https://blog.csdn.net/qq_30141957/article/details/81273829 项目中,有些函数需要处理某个服务的返回结果,而在对函数单元测试的时候,又不能 ...

  2. 纪念google reader

    2013年3月14日早上,谷歌在其官方博客宣布,2005年推出的 Google Reader 将在7月1号关闭. google reader的历史 以下搞自维基百科http://zh.wikipedi ...

  3. Android中创建option menu

    1.首先在res目录下新建一个menu文件夹,右击res目录->New->Directory,输入文件夹名menu,点击OK. 接着在这个文件夹下再新建一个名叫main的菜单文件,右击me ...

  4. 【树莓派】在树莓派的Android系统中安装APK应用

    树莓派3 Android TV安装APK应用教程 本文摘自:http://www.mz6.net/news/android/6867.html 树莓派3 Android TV怎样安装软件?对于熟悉AD ...

  5. 微软BI 之SSRS 系列 - 如何实现报表标签的本地化 - 中文和英文的互换

    SSRS 中并没有直接提供本地化的配置方式,因此在 SSRS 中实现本地化,比如有英文标题还有可选的中文标题,就需要通过其它的方式来解决. 比如默认是这样的英文标题 - 但是本地中方用户可能比较喜欢看 ...

  6. linux cp 命令详解

    /home/lee#cp --help 用法:cp [选项]... 来源 目的地 或:cp [选项]... 来源... 目录 或:cp [选项]... --target-directory=目录 来源 ...

  7. Rabbit mq订阅方式获取消息并可设置持久化

    Rabbit 通过方式获取消息:订阅方式事实上是向queue注冊consumer,通过rpc向queue server发送注冊consumer的消息.rabbitMQ Server在收到消息后,依据消 ...

  8. MVC+WCF框架下广告位管理——文件上传

    广告位是站点中不可缺少的内容之中的一个.也是能直接给我们站点带来经济收益的内容之中的一个. 好的广告位不仅不会强宾压主,而会为我们的站点锦上添花.起到画龙点睛的作用.因此设计好广告位也是开发过程中一大 ...

  9. C语言中连接器介绍

    在C语言中.一个重要的思想就是分别编译.即若干个源程序能够在不同的时候单独进行编译.然后在恰当的时候整合到一起.可是连接器通常是与C编译器分离的,连接器怎样做到把若干个C源程序合并成一个总体呢? 典型 ...

  10. Java的PriorityQueue

    转载请注明原文地址:http://www.cnblogs.com/ygj0930/p/6538654.html  优先队列实质上就是数据结构中的最小堆,而堆从概念图来看类似于一棵二叉树,从具体实现来说 ...