Intent----android中的伟大邮差
在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中的伟大邮差的更多相关文章
- (转)Android 中LocalBroadcastManager的使用方式
发表于2个月前(2014-11-03 22:05) 阅读(37) | 评论(0) 0人收藏此文章, 我要收藏 赞0 1月10日 #长沙# OSC 源创会第32期开始报名 摘要 android中广播 ...
- Android中Intent的用法总结
Intent只在Android中特有,我把它比作一种运载工具,就像飞机一样,会把一些人带到某个地方,而且如果需要的话,还可以找到机上有哪些人员(数据),这就需要另外一些设备来支持(如:Bundle), ...
- Android中如何使用Intent在Activity之间传递对象[使用Serializable或者Parcelable]
http://blog.csdn.net/cjjky/article/details/6441104 在Android中的不同Activity之间传递对象,我们可以考虑采用Bundle.putSeri ...
- Android中Intent传递对象的两种方法(Serializable,Parcelable)
今天要给大家讲一下Android中 Intent中如何传递对象,就我目前所知道的有两种方法,一种是Bundle.putSerializable(Key,Object);另一种是 Bundle.putP ...
- Android中Intent传值与Bundle传值的区别详解
Android中Intent传值与Bundle传值的区别详解 举个例子我现在要从A界面跳转到B界面或者C界面 这样的话 我就需要写2个Intent如果你还要涉及的传值的话 你的Intent就要写两 ...
- Android中的Intent Filter匹配规则介绍
本文主要介绍了隐式Intent匹配目标组件的规则,若有叙述不清晰或是不准确的地方希望大家指出,谢谢大家: ) 1. Intent简介 Intent用于在一个组件(Component,如Activity ...
- Android中的Intent详解
前言: 每个应用程序都有若干个Activity组成,每一个Activity都是一个应用程序与用户进行交互的窗口,呈现不同的交互界面.因为每一个Acticity的任务不一样,所以经常互在各个Activi ...
- Android中Intent组件详解
Intent是不同组件之间相互通讯的纽带,封装了不同组件之间通讯的条件.Intent本身是定义为一个类别(Class),一个Intent对象表达一个目的(Goal)或期望(Expectation),叙 ...
- android中使用Intent在activity之间传递数据
android中intent传递数据的简单使用: 1.使用intent传递数据: 首先将需要传递的数据放入到intent中 Intent intent = new Intent(MainActivit ...
- 【转】Android中intent传递对象和Bundle的用法
原文网址:http://blog.csdn.net/lixiang0522/article/details/8642202 android中的组件间传递的对象一般实现Parcelable接口,当然也可 ...
随机推荐
- MyBatis对于Java对象里的枚举类型处理
平时咱们写程序实体类内或多或少都会有枚举类型属性,方便嘛.但是mybatis里怎么处理他们的增删改查呢? 要求: 插入的时候,会用枚举的定义插入数据库,我们希望在数据库中看到的是数字或者其他东西: 查 ...
- ionic3+angular5页面间传递参数
一.从一个页面跳转到另一个页面的方法 1.引入服务 import { NavController } from 'ionic-angular'; 2.初始化 constructor(public na ...
- iOS编程(双语版)-视图-Frame/Bounds/Center
1. Frame 每个视图都有一个frame属性,它是CGRect结构,它描述了视图所在的矩形在其父视图中的位置. (屏幕坐标系默认的原点在左上角,x轴向右伸展,y轴向下伸展) 设置frame通常通过 ...
- mahout基于Hadoop的CF代码分析(转)
来自:http://www.codesky.net/article/201206/171862.html mahout的taste框架是协同过滤算法的实现.它支持DataModel,如文件.数据库.N ...
- Hive Web Interface的安装
Hive Web Interface,简称hwi,是Hive的Web接口. 首先,安装ant,下载ant,解压,并在/etc/profile中设置: export ANT_HOME=/opt/apac ...
- Customize Web Sessions List
To customize Fiddler's Web Sessions List, add rules using FiddlerScript to the OnBeforeRequest funct ...
- 数组的翻转(非reverse())
方法一: var arr = [1,2,3,4]; var arr2 = []; while(arr.length) { var num = arr.pop(); //删除数组最后一个元素并返回被删除 ...
- 【leetcode】solution in java——Easy1
转载请注明原文地址:http://www.cnblogs.com/ygj0930/p/6409067.html 1:Hamming distance The Hamming distance betw ...
- cocos2d-js V3.0 V3.1使用DragonBones
DragonBones是Adobe支持的一个开源项目,用于制作和播放骨骼动画,官网地址是:http://dragonbones.effecthub.com/.DragonBones首先在Flash和S ...
- ps 如何制作动态打字图?
1.情景展示 有几句话,想以打字的形式出现,而不是干巴巴的几个字,如何实现这个有趣的效果呢? 2.解决方案 第一步:录制屏幕:将想展示的文字逐字打出来-->保存: 第二步:将录制的视频使用p ...