
- 作 用
- 解决Android应用各项组件的通讯
- 提供信息
- 组件互相调用的相关信息
- 实现目的
- 调用者与被调用者之间的解耦
- 中文名
- 意图
- 性 质
- 媒体中介
- 外文名
- intent
-
Intent
2013-08-14 17:49:29在android中,intent就像是一个邮差,辛勤高效的在各个组件之间来回穿梭。我们可以通过它启动一个Activity或者Service,或者是发送给广播组件,又或者是与后台的Service进行通信。所谓的Intent,字面意思就是"意图,...在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
2013-04-16 15:37:00看似尋常最奇崛,成如容易卻艱辛。北宋.... 看似普通的事情其实最不同寻常,并不是简简单单就可以做好的;成功看起来似乎很容易,而成功的过程却充满着艰辛。...对于我们认为很普通的事情,不屑一顾,就永远不会有长进...http://blog.csdn.net/liuhe688/article/details/7050868
看似尋常最奇崛,成如容易卻艱辛。北宋.王安石
看似普通的事情其实最不同寻常,并不是简简单单就可以做好的;成功看起来似乎很容易,而成功的过程却充满着艰辛。
对于我们认为很普通的事情,不屑一顾,就永远不会有长进,脚踏实地,就离成功又近一步;成功并不像看到的那么容易,寻找捷径是不可取的,我们往往要比别人付出更多的辛勤和努力。
今天我们来讲一下Android中Intent的原理和应用。
前面我们总结了几个Android中重要组件,相信大家对于这些组件已经有了清晰的认识,我们就来看一下几个常见的操作:
启动一个Activity:Context.startActivity(Intent intent);
启动一个Service:Context.startService(Intent service);
绑定一个Service:Context.bindService(Intent service, ServiceConnection conn, int flags);
发送一个Broadcast:Context.sendBroadcast(Intent intent);
我们发现,在这些操作中,都有一个Intent参与其中,看起来像是一个非常重要的组件,那么Intent到底是什么呢?
简单来说,Intent是系统各组件之间进行数据传递的数据负载者。当我们需要做一个调用动作,我们就可以通过Intent告诉Android系统来完成这个过程,Intent就是调用通知的一种操作。
Intent有几个重要的属性,下面我们将会逐一介绍:
1.action,要执行的动作
对于有如下声明的Activity:
- <activity android:name=".TargetActivity">
- <intent-filter>
- <action android:name="com.scott.intent.action.TARGET"/>
- <category android:name="android.intent.category.DEFAULT"/>
- </intent-filter>
- </activity>
- public void gotoTargetActivity(View view) {
- Intent intent = new Intent("com.scott.intent.action.TARGET");
- startActivity(intent);
- }
当我们为Intent指定相应的action,然后调用startActivity方法后,系统会根据action跳转到对应的Activity。
除了自定义的action之外,Intent也内含了很多默认的action,随便列举几个:
- public static final String ACTION_MAIN = "android.intent.action.MAIN";
- public static final String ACTION_VIEW = "android.intent.action.VIEW";
- public static final String ACTION_WEB_SEARCH = "android.intent.action.WEB_SEARCH";
- public static final String ACTION_CALL = "android.intent.action.CALL";
每一个action都有其特定的用途,下文也会使用到它们。
2.data和extras,即执行动作要操作的数据和传递到目标的附加信息
下面就举一个与浏览器交互的例子:
- /**
- * 打开指定网页
- * @param view
- */
- public void invokeWebBrowser(View view) {
- Intent intent = new Intent(Intent.ACTION_VIEW);
- intent.setData(Uri.parse("http://www.google.com.hk"));
- startActivity(intent);
- }
- /**
- * 进行关键字搜索
- * @param view
- */
- public void invokeWebSearch(View view) {
- Intent intent = new Intent(Intent.ACTION_WEB_SEARCH);
- intent.putExtra(SearchManager.QUERY, "android"); //关键字
- startActivity(intent);
- }
我们注意到,在打开网页时,为Intent指定一个data属性,这其实是指定要操作的数据,是一个URI的形式,我们可以将一个指定前缀的字符串转换成特定的URI类型,如:“http:”或“https:”表示网络地址类型,“tel:”表示电话号码类型,“mailto:”表示邮件地址类型,等等。例如,我们要呼叫给定的号码,可以这样做:
- public void call(View view) {
- Intent intent = new Intent(Intent.ACTION_CALL);
- intent.setData(Uri.parse("tel:12345678"));
- startActivity(intent);
- }
那么我们如何知道目标是否接受这种前缀呢?这就需要看一下目标中<data/>元素的匹配规则了。
在目标<data/>标签中包含了以下几种子元素,他们定义了url的匹配规则:
android:scheme 匹配url中的前缀,除了“http”、“https”、“tel”...之外,我们可以定义自己的前缀
android:host 匹配url中的主机名部分,如“google.com”,如果定义为“*”则表示任意主机名
android:port 匹配url中的端口
android:path 匹配url中的路径
我们改动一下TargetActivity的声明信息:
- <activity android:name=".TargetActivity">
- <intent-filter>
- <action android:name="com.scott.intent.action.TARGET"/>
- <category android:name="android.intent.category.DEFAULT"/>
- <data android:scheme="scott" android:host="com.scott.intent.data" android:port="7788" android:path="/target"/>
- </intent-filter>
- </activity>
- public void gotoTargetActivity(View view) {
- Intent intent = new Intent("com.scott.intent.action.TARGET");
- intent.setData(Uri.parse("scott://com.scott.intent.data:7788/target"));
- startActivity(intent);
- }
不过有时候对path限定死了也不太好,比如我们有这样的url:(scott://com.scott.intent.data:7788/target/hello)(scott://com.scott.intent.data:7788/target/hi)
这个时候该怎么办呢?我们需要使用另外一个元素:android:pathPrefix,表示路径前缀。
我们把android:path="/target"修改为android:pathPrefix="/target",然后就可以满足以上的要求了。
而在进行搜索时,我们使用了一个putExtra方法,将关键字做为参数放置在Intent中,我们成为extras(附加信息),这里面涉及到了一个Bundle对象。
Bundle和Intent有着密不可分的关系,主要负责为Intent保存附加参数信息,它实现了android.os.Paracelable接口,内部维护一个Map类型的属性,用于以键值对的形式存放附加参数信息。在我们使用Intent的putExtra方法放置附加信息时,该方法会检查默认的Bundle实例为不为空,如果为空,则新创建一个Bundle实例,然后将具体的参数信息放置到Bundle实例中。我们也可以自己创建Bundle对象,然后为Intent指定这个Bundle即可,如下:
- public void gotoTargetActivity(View view) {
- Intent intent = new Intent("com.scott.intent.action.TARGET");
- Bundle bundle = new Bundle();
- bundle.putInt("id", 0);
- bundle.putString("name", "scott");
- intent.putExtras(bundle);
- startActivity(intent);
- }
- Bundle bundle = intent.getExtras();
- int id = bundle.getInt("id");
- String name = bundle.getString("name");
当然我们也可以使用Intent的getIntExtra和getStringExtra方法获取,其数据源都是Intent中的Bundle类型的实例对象。
前面我们涉及到了Intent的三个属性:action、data和extras。除此之外,Intent还包括以下属性:
3.category,要执行动作的目标所具有的特质或行为归类
例如:在我们的应用主界面Activity通常有如下配置:
- <category android:name="android.intent.category.LAUNCHER" />
几个常见的category如下:
Intent.CATEGORY_DEFAULT(android.intent.category.DEFAULT) 默认的category
Intent.CATEGORY_PREFERENCE(android.intent.category.PREFERENCE) 表示该目标Activity是一个首选项界面;
Intent.CATEGORY_BROWSABLE(android.intent.category.BROWSABLE)指定了此category后,在网页上点击图片或链接时,系统会考虑将此目标Activity列入可选列表,供用户选择以打开图片或链接。
在为Intent设置category时,应使用addCategory(String category)方法向Intent中添加指定的类别信息,来匹配声明了此类别的目标Activity。
4.type:要执行动作的目标Activity所能处理的MIME数据类型
例如:一个可以处理图片的目标Activity在其声明中包含这样的mimeType:
- <data android:mimeType="image/*" />
intent.setData("file:///sdcard/image.data");
intent.setType("image/jpg");
你会发现数据被清空了,反之。。。,如果想同时设置数据和类型就得用setDataAndType(Uri data, String type)5.component,目标组件的包或类名称
在使用component进行匹配时,一般采用以下几种形式:
- intent.setComponent(new ComponentName(getApplicationContext(), TargetActivity.class));
- intent.setComponent(new ComponentName(getApplicationContext(), "com.scott.intent.TargetActivity"));
- intent.setComponent(new ComponentName("com.scott.other", "com.scott.other.TargetActivity"));
其中,前两种是用于匹配同一包内的目标,第三种是用于匹配其他包内的目标。需要注意的是,如果我们在Intent中指定了component属性,系统将不会再对action、data/type、category进行匹配。
注意:
inteng filter对象里面ACTION和CATEGORY都可以设置成多个,例如
如果一个页面有多个ACTION 例如:
页面2的
<activity
android:name="com.example.myfirstapp.SecondActivity"
android:label="@string/title_activity_second" >
<intent-filter>
<action android:name="com.example.myfirstapp.second"/>
<action android:name="com.example.myfirstapp.three"/>
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>我用sedIntent.setAction("com.example.myfirstapp.three");和sedIntent.setAction("com.example.myfirstapp.second");都能实现其跳转,即能找到该ACTIVITY
如果多个category也可以被找到,他们都算或的关系,但是,INTENT对象里面如果添加多个category的话,那么必须全部都被满足后才可以找到对应的ACTIVITY
例如:
<activity
android:name="com.example.myfirstapp.SecondActivity"
android:label="@string/title_activity_second" >
<intent-filter>
<action android:name="com.example.myfirstapp.second"/>
<action android:name="com.example.myfirstapp.three"/>
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.TAB" />
<category android:name="android.intent.category.ALTERNATIVE" />
</intent-filter>
</activity>我用
Intent sedIntent=new Intent();
可以访问该ACTIVITY,但是:
sedIntent.addCategory("android.intent.category.DEFAULT");
sedIntent.addCategory("android.intent.category.ALTERNATIVE");
sedIntent.setAction("com.example.myfirstapp.three");
startActivity(sedIntent);
Intent sedIntent=new Intent();
sedIntent.addCategory("android.intent.category.DEFAULT");
sedIntent.addCategory("android.intent.category.APP_BROWSER");
sedIntent.setAction("com.example.myfirstapp.three");
startActivity(sedIntent);
会报错,说页面找不到
还有一种情况是
<activity
android:name="com.example.myfirstapp.SecondActivity"
android:label="@string/title_activity_second" >
<intent-filter>
<action android:name="com.example.myfirstapp.second"/>
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
<intent-filter>
<action android:name="com.example.myfirstapp.three"/>
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
随便用哪种方式去启动,只有满足其中一个适配就可以找到。
sedIntent.setAction("com.example.myfirstapp.three");和sedIntent.setAction("com.example.myfirstapp.second");都能实现其跳转,即能找到该ACTIVITY
Intent的中文意思是“意图,目的”的意思,可以理解为不同组件之间通信的“媒介”或者“信使”。
目标组件一般要通过Intent来声明自己的条件,一般通过组件中的<intent-filter>元素来过滤。
Intent在由以下几个部分组成:动作(action),数据(data),分类(Category),类型(Type),组件(Component),和扩展信息(Extra)。
Intent在寻找目标组件的时候有两种方法:第一,通过组件名称直接指定;第二,通过Intent Filter过滤指定
Intent启动不同组件的方法
组件名称
方法名称
Activity
startActivity()
startActivityForResult()
Service
startService()
bindService()
Broadcasts
sendBroadcast()
sendOrderedBroadcast()
sendStickyBroadcast()
常见的Activity Action Intent常量
常量名称
常量值
意义
ACTION_MAIN
android.intent.action.MAIN
应用程序入口
ACTION_VIEW
android.intent.action.VIEW
显示数据给用户
ACTION_ATTACH_DATA
android.intent.action.ATTACH_DATA
指明附加信息给其他地方的一些数据
ACTION_EDIT
android.intent.action.EDIT
显示可编辑的数据
ACTION_PICK
android.intent.action.PICK
选择数据
ACTION_CHOOSER
android.intent.action.CHOOSER
显示一个Activity选择器
ACTION_GET_CONTENT
android.intent.action.GET_CONTENT
获得内容
ACTION_DIAL
android.intent.action.GET_CONTENT
显示打电话面板
ACITON_CALL
android.intent.action.DIAL
直接打电话
ACTION_SEND
android.intent.action.SEND
直接发短信
ACTION_SENDTO
android.intent.action.SENDTO
选择发短信
ACTION_ANSWER
android.intent.action.ANSWER
应答电话
ACTION_INSERT
android.intent.action.INSERT
插入数据
ACTION_DELETE
android.intent.action.DELETE
删除数据
ACTION_RUN
android.intent.action.RUN
运行数据
ACTION_SYNC
android.intent.action.SYNC
同步数据
ACTION_PICK_ACTIVITY
android.intent.action.PICK_ACTIVITY
选择Activity
ACTION_SEARCH
android.intent.action.SEARCH
搜索
ACTION_WEB_SEARCH
android.intent.action.WEB_SEARCH
Web搜索
ACTION_FACTORY_TEST
android.intent.action.FACTORY_TEST
工厂测试入口点
常见的BroadcastIntent Action常量
BroadcastIntent Action字符串常量
描述
ACTION_TIME_TICK
系统时间每过一分钟发出的广播
ACTION_TIME_CHANGED
系统时间通过设置发生了变化
ACTION_TIMEZONE_CHANGED
时区改变
ACTION_BOOT_COMPLETED
系统启动完毕
ACTION_PACKAGE_ADDED
新的应用程序apk包安装完毕
ACTION_PACKAGE_CHANGED
现有应用程序apk包改变
ACTION_PACKAGE_REMOVED
现有应用程序apk包被删除
ACTION_UID_REMOVED
用户id被删除
Intent的Action和Data属性匹配
Action属性
Data属性
说明
ACTION_VIEW
content://contacts/people/1
显示id为1的联系人信息
ACTION_DIAL
content://contacts/people/1
将id为1的联系人电话号码显示在拨号界面中
ACITON_VIEW
显示电话为123的联系人信息
ACTION_VIEW
在浏览器中浏览该网站
ACTION_VIEW
播放MP3
ACTION_VIEW
geo:39.2456,116.3523
显示地图
常见的Category常量
Category字符串常量
描述
CATEGORY_BROWSABLE
目标Activity能通过在网页浏览器中点击链接而激活(比如,点击浏览器中的图片链接)
CATEGORY_GADGET
表示目标Activity可以被内嵌到其他Activity当中
CATEGORY_HOME
目标Activity是HOME Activity,即手机开机启动后显示的Activity,或按下HOME键后显示的Activity
CATEGORY_LAUNCHER
表示目标Activity是应用程序中最优先被执行的Activity
CATEGORY_PREFERENCE
表示目标Activity是一个偏爱设置的Activity
常见的Extra常量
Extra键值字符串常量
描述
EXTRA_BCC
装有邮件密送地址的字符串数组
EXTRA_CC
装有邮件抄送地址的字符串数组
EXTRA_EMAIL
装有邮件发送地址的字符串数组
EXTRA_INTENT
使用ACTION_PICK_ACTIVITY动作时装有Intent选项的键
EXTRA_KEY_EVENT
触发该Intent的案件的KeyEvent对象
EXTRA_PHONE_NUMBER
使用拨打电话相关的Action时,电话号码字符串的键,类型为String
EXTRA_SHORTCUT_ICON
使用ACTION_CREATE_SHORTCUT在HomeActivity创建快捷方式时,对快捷方式的描述信息。其中ICON和ICON_RESOURCE描述的是快捷方式的图标,类型分别为Bitmap和ShortcutIconResource。INTENT描述的是快捷方式相对应的Intent对象。NAME描述的是快捷方式的名字。
EXTRA_SHORTCUT_ICON_RESOURCE
EXTRA_SHORTCUT_INTENT
EXTRA_SHORTCUT_NAME
EXTRA_SUBJECT
描述信息主题的键
EXTRA_TEXT
使用ACTION_SEND动作时,用来描述要发送的文本信息,类型为CharSequence
EXTRA_TITLE
使用ACTION_CHOOSER动作时,描述对话框标题的键,类型为CharSequence
EXTRA_UID
使用ACTION_UID_REMOVED动作时,描述删除的用户id的键,类型为int
Android.telephony包中的类
类名
描述
CellLocation
表示设备位置的抽象类
PhoneNumberFormattingTextWather
监视一个TextView控件,如果有电话号码输入,则用formatNumber()方法处理电话号码
PhoneNumberUtils
包含各种处理电话号码字符串的使用工具
PhoneStateListener
监视手机中电话状态变化的监听类
ServiceState
包含电话状态和相关的服务信息
TelephonyManager
提供对手机中电话服务信息的访问
与短信服务相关的类主要在包android.telephony.gsm中
类名
描述
GsmCellLocation
表示GSM手机的基站位置
SmsManager
管理各种短信操作
SmsMessage
表示具体的短信
-
Intent以及IntentFilter详解
2016-09-23 16:05:44在Android中有四大组件,这些组件中有三个组件与Intent相关,可见Intent在Android整个生态中的地位高度。Intent是信息的载体,用它可以去请求组件做相应的操作,但是相对于这个功能,Intent本身的结构更值得我们去...转载注明出处:http://blog.csdn.net/xiaohanluo/article/details/52637520
1. 前言
在Android中有四大组件,这些组件中有三个组件与Intent相关,可见Intent在Android整个生态中的地位高度。Intent是信息的载体,用它可以去请求组件做相应的操作,但是相对于这个功能,Intent本身的结构更值得我们去研究。
2. Intent与组件
Intent促进了组件之间的交互,这对于开发者非常重要,而且它还能做为消息的载体,去指导组件做出相应的行为,也就是说Intent可以携带数据,传递给Activity/Service/BroadcastReceiver。
- 启动Activity。Activity可以简单的理解为手机屏幕中的一个页面,你可以通过将Intent传入
startActivity方法
来启动一个Activity的实例,也就是一个页面,同时,Intent也可以携带数据,传递给新的Activity。如果想要获取新建的Activity执行结果,可以通过onActivityResult()
方法去启动Activity。 - 启动Service。Service是一个不呈现交互画面的后台执行操作组件,可以通过将Intent穿入
startService()
方法来启动一个Service来启动服务。 - 传递广播BroadCast。广播是任何应用都可以接收到的消息,通过将Intent传递给
sendBroadcast()
、sendOrderedBroadcast()
或sendStickyBroadcast()
方法,可以将广播传递接收方。
3. Intent类型
在Android中,Intent分为两种类型,显式和隐式。
-
显式Intent,可以通过类名来找到相应的组件,在应用中用显式Intent去启动一个组件,通常是因为我们知道这个组件(Activity或者Service)的名字。如下代码,我们知道具体的
Activity
的名字,要启动一个新的Activity,下面就是用的显示Intent。Intent intent = new Intent(context,XXActivity.class); startActivity(intent);
-
隐式Intent,不指定具体的组件,但是它会声明将要执行的操作,从而匹配到相应的组件。最简单的Android中调用系统拨号页面准备打电话的操作,就是隐式Intent。
Intent intent = new Intent(Intent.ACTION_DIAL); Uri data = Uri.parse("tel:" + "135xxxxxxxx"); intent.setData(data); startActivity(intent);
使用显示Intent去启动Activity或者Service的时候,系统将会立即启动Intent对象中指定的组件。
使用隐式Intent的时候,系统通过将Intent对象中的IntentFilter与组件在
AndroidManifest.xml
或者代码中动态声明的IntentFilter进行比较,从而找到要启动的相应组件。如果组件的IntentFilter与Intent中的IntentFilter正好匹配,系统就会启动该组件,并把Intent传递给它。如果有多个组件同时匹配到了,系统则会弹出一个选择框,让用户选择使用哪个应用去处理这个Intent,比如有时候点击一个网页链接,会弹出多个应用,让用户选择用哪个浏览器去打开该链接,就是这种情况。IntentFilter通常是定义在
AndroidManifest.xml
文件中,也可以动态设置,通常是用来声明组件想要接受哪种Intent。例如,你如果为一个Activity设置了IntentFilter,你就可以在应用内或者其他应用中,用特定的隐式Intent来启动这个Activity,如果没有为Activity设置IntentFilter,那么你就只能通过显示Intent来启动这个Activity。注意,为了确保系统的稳定性,官方建议使用显示Intent来启动Service,同时也不要为Service设置IntentFilter,因为如果使用隐式Intent去启动Service,我们并不知道那些服务会响应Intent,而且由于服务大多是不可见的,我们也不知道那些服务被启动了,这是非常危险的。在Android 5.0(API 21)以后,如果使用隐式的Intent去调用
bindService()
方法,系统会抛出异常。4. Intent的属性
Intent作为消息的载体,系统根据它去决定启动哪个具体的组件同时将组件执行中需要的信息传递过去。Intent能够包含的属性有Component、Action、Data、Category、Extras、Flags,关于这些属性的更详细信息可查看这里。
- Component,要启动的组件名称。这个属性是可选的,但它是显式Intent的一个重要属性,设置了这个属性后,该Intent只能被传递给由
Component
定义的组件。隐式Intent是没有该属性的,系统是根据其他的信息(例如,Action、Data等)来判断该Intent应该传递给哪个组件。这个属性是目标的组件的具体名称(完全限定类名),例如,com.example.DemoActivity。该属性可以通过setComonentName()
、setClass()
、setClassName()
或者Intent的构造函数来设置。 - Action,表明执行操作的字符串。它会影响Intent的其余信息,比如Data、Extras。该属性可以通过
setAction()
方法或者Intent的构造函数来设置。用户可以自定义这个属性,也可以使用系统中已经有的Action值。下面列出启动Activity时候的一些通用Action属性。- ACTION_VIEW,当有一些信息需要展示出来,可以设置Intent的Action为这个值,并调用startActivity()方法
- ACTION_SEND,当用户有一些信息需要分享到其他应用,可以设置Intent的Action为这个值,并调用startActivity()方法
- ACTION_DIAL,拨打电话,可以设置Intent的Action为这个值,并调用startActivity()方法
- ACTION_EDIT,编辑某些文件,可以设置Intent的Action为这个值,并调用startActivity()方法
- Data,它是待操作数据的引用URI或者数据MIME类型的URI,它的值通常与Intent的
Action
有关联。比如,如果设置Action的值为ACTION_EDIT
,那么Data
的值就必须包含被编辑文档的URI。当我们创建Intent的时候,设置MIME类型非常重要。例如,一个可以显示图片的Activity可能不能播放音频,图片和音频的URI非常类似,如果我们设置了MIME类型,可以帮助系统找到最合适的组件接受Intent。有时候,MIME类型也可以从URI判断出来,例如当Data是一个包含content:
字符串的URI时候,可以明确的知道,待处理的数据存在设备中,而且由ContentProvider控制。-
使用
setData()
方法设置数据引用的URI,使用setType()
方法设置数据的MIME类型,使用setDataAndType()
方法同时设置这两个属性。 -
注意:如果想要设置两个的属性,直接用
setDataAndType()
方法,不要同时调用setData()
和setType()
方法,因为这两个方法设置的值会相互覆盖public Intent setData(Uri data) { mData = data; mType = null; return this; } public Intent setType(String type) { mData = null; mType = type; return this; }
-
- Category,这个属性是对处理该Intent组件信息的补充。它是一个
ArraySet
类型的容器,所以可以向里面添加任意数量的补充信息,同时,Intent没有设置这个属性不会影响解析组件信息。可以通过addCategory()
方法来设置该属性。下面列出一些常用的Category的值。- CATEGORY_BROWSABLE,设置Category为该值后,在网页上点击图片或链接时,系统会考虑将此目标Activity列入可选列表,供用户选择以打开图片或链接。
- CATEGORY_LAUNCHER,应用启动的初始Activity,这个Activity会被添加到系统启动launcher当中。
以上列出的这些关于Intent的属性(Component、Action、Data、Category)可以帮助系统来确定具体的组件,但是有一些Intent的属性,不会影响到组件的确定。
- Extras,以key-value键值对的形式来存储组件执行操作过程中需要的额外信息,可以调用
putExtra()
方法来设置该属性,这个方法接受两个参数,一个是key,一个是value。也可以通过实例化一个储存额外信息的Bundle对象,然后调用putExtras()
方法将我们实例化的Bundle添加到Intent中。 - Flags,这个属性可以指示系统如何启动一个Activity,以及启动之后如何处理。例如Activity属于哪一个task(参考Activity的四种启动方式)。
5. 显式Intent示例
上文说到,显式Intent是用于启动某个特定的组件(Activity或者Service)的Intent,穿创建显式的Intent的时候需要设置组件名称(Component)属性,其他的属性都是可选属性。
// fileUrl是一个URL字符串,例如 "http://www.example.com/image.png" Intent downloadIntent = new Intent(context, DownloadService.class); downloadIntent.setData(Uri.parse(fileUrl)); startService(downloadIntent);
这里的Intent的构造函数传入了两个参数,context和组件名(Component),调用了
startService()
方法后,会在当前的应用中启动DownloadService
这个服务。
显示Intent中设置的组件名(Component)需要在AndroidManifest.xml进行注册,所以它一般用来启动当前应用内的组件。6. 隐式Intent示例
隐式Intent比显示的Intent会复杂一些,它既可以启动当前应用内的组件,也可以启动当前应用外的组件。如果当前应用无法处理隐式Intent,但是其他应用中的组件可以处理,那么系统会弹框让用户选择启动哪个应用中的组件。
例如,如果用户有内容想分享给其他应用,就创建一个Intent,将它的
Action
属性设置为ACTION_SEND
,然后将要分享的内容设置到Extras
属性中,然后调用startActivity()
方法,用户就可以选择将内容分享到哪一个应用。注意,如果没有任何应用能处理用户发送的隐形Intent,调用组件失败,应用可能会崩溃。调用
resolveActivity()
方法可以确认是否有Activity
能够处理这个Intent,如果返回为非空,那么至少有一个组件能够处理这个Intent,调用startActivity()
就很安全了;如果返回的是空(null),那么说明没有组件能够处理这个Intent,这个时候就不应该使用这个隐式的Intent了。// 要将textMessage信息分享出去 Intent sendIntent = new Intent(); sendIntent.setAction(Intent.ACTION_SEND); sendIntent.putExtra(Intent.EXTRA_TEXT, textMessage); sendIntent.setType("text/plain"); // 确认是否有组件能够处理这个隐式Intent if (sendIntent.resolveActivity(getPackageManager()) != null) { startActivity(sendIntent); }
调用
startActivity()
传入一个隐式Intent时候,系统会检查设备中所有的应用,确定哪些应用可以处理这个隐式的Intent(含有startActivity()
操作并携带text/plain
类型的Intent),如果只有一个应用可以处理这个Intent,那么直接唤起这个应用,并将Intent传给它;如果有多个应用可以处理这个Intent,那么系统会弹出一个选择框,让用户选择唤起哪个应用。7. 强制唤起选择框
上文说了,如果多个应用可以处理同一个隐式Intent,系统会弹出选择框,让用户选择唤起哪个应用,并设置该应用为默认的打开方式,以后就不会弹出选择框了。如果用户希望以后一直使用该用户处理这个隐式Intent(比如打开网页,用户通常会倾向于使用同一个web浏览器),那么十分方便。
但是如果用户想每一次都用不同的应用去处理这个隐式的Intent的,就应该每次弹出选择框,用户可以在选择框中选择唤起的应用,但是无法设置默认的打开方式。例如,当用户想根据当前的位置将内容分享到不同的应用,所以每次都需要弹出选择框。
用户需要通过
Intent.createChooser()
创建一个Intent,然后调用startActivity()
。Intent sendIntent = new Intent(Intent.ACTION_SEND); ... // 分享的标题 String title = getResources().getString(R.string.chooser_title); // 创建一个调用选择框的Intent Intent chooser = Intent.createChooser(sendIntent, title); // 确认是否有应用可以处理这个Intent if (sendIntent.resolveActivity(getPackageManager()) != null) { startActivity(chooser); }
8. 接受隐式Intent
想配置你的应用可以处理哪些隐式的Intent,需要在AndroidManifest.xml文件中使用
<intent-filter>
标签为组件设置一个或者多个过滤器。每一个过滤器基于Action
、Data
、Category
来指定自身可以处理的Intent类型。如果隐式Intent的能够匹配到用户设置的其中一个过滤器,系统才能唤起这个应用相应的组件并将Intent传递给这个组件。组件应该为为一个它可以处理的操作单独设置一个处理器。例如,相册中的Activity可能有两个过滤器,一个过滤器对应浏览照片的操作,另一个过滤器对应编辑照片的操作。当这个Activity被启动的时候,根据Intent中携带的信息来决定执行哪种操作。
每一个过滤器是在AndroidManifest.xml使用
<intent-filter>
标签来定义的,嵌套在组件标签中,例如<activity>
、<service>
标签。在<intent-filter>
标签中,用户可以使用一下三个属性中的一个或者多个来指定可以接受的Intent。<action>
,在这个属性中,声明该组件可以执行的操作。该值必须是关于操作的一个字符串,并不是类常量<data>
,使用一个或者多个数据URI(scheme、host、port、path等等)和数据的MIME类型来指定接受的数据类型<category>
,声明接受的Intent类型
Activity组件要接受隐式Intent,它必须有一个
<category>
属性为CATEGORY_DEFAULT
的过滤器,因为startActivity()和startActivityForResult()
方法处理Intent时候,默认的认为接受组件有一个<category>
属性为CATEGORY_DEFAULT
的过滤器。如果一个Activity组件不声明这样一个过滤器,它就接收不到隐式Intent。例如,以下代码声明了一个Activity组件,这个组件可以处理
action
属性为ACTION_SEND
,数据类型是文本(text/plain)的隐式Intent。<activity android:name="ShareActivity"> <intent-filter> <action android:name="android.intent.action.SEND"/> <category android:name="android.intent.category.DEFAULT"/> <data android:mimeType="text/plain"/> </intent-filter> </activity>
用户也可以创建一个包含多个
<action>
、<data>
、<category>
标签的过滤器,创建时候仅需要确定该组件能够处理过滤器定义的操作即可。如果是根据
<action>
、<data>
、<category>
标签的组合来处理多个Intent,那么需要为这个组件声明多个过滤器。系统会以这三个属性将隐式Intent与所有组件声明的过滤器进行对比,如果这三个属性全部能够匹配上,系统才有可能将这个隐式Intent传递给这个组件,因为如果多个应用的组件都能匹配上会弹出选择框,让用户选择一个应用去处理这个隐式Intent。
为了避免无意中启动了其他的Service,所以在应用内,建议一直使用显示的Intent去启动服务,这样就不必再AndroidManifest.xml文件中为Service声明过滤器了。
对于Activity的过滤器,必须在AndroidManifest.xml文件中声明,也可以不声明,直接使用显示Intent唤起Activity组件。
广播接收器的过滤器声明可以在AndroidManifest.xml文件中声明,也可以使用
registerReceiver()
方法动态注册,使用完毕后,使用unregisterReceiver()
方法动态注销。9. 过滤器声明示例
下面一些过滤器的声明能够帮助你更好的理解。
<activity android:name="MainActivity"> <!-- 该Activity是该应用的启动入口页面,它会被储存在系统的launcher列表中 --> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <activity android:name="ShareActivity"> <!-- 该Activity能够处理ACTION_SEND行为且数据类型为text/plain的隐式Intent --> <intent-filter> <action android:name="android.intent.action.SEND"/> <category android:name="android.intent.category.DEFAULT"/> <data android:mimeType="text/plain"/> </intent-filter> <!-- 该Activity能够处理ACTION_SEND行为且数据类型是媒体内容的隐式Intent --> <intent-filter> <action android:name="android.intent.action.SEND"/> <action android:name="android.intent.action.SEND_MULTIPLE"/> <category android:name="android.intent.category.DEFAULT"/> <data android:mimeType="image/*"/> <data android:mimeType="video/*"/> </intent-filter> </activity>
第一个名为MainActivity的组件,是应用的启动入口页面,当用户点击应用图标,该Activity会被启动。
- android.intent.action.MAIN,表示该Activity是应用的启动入口,且不需要任何Intent携带的数据。
- android.intent.category.LAUNCHER,表示将该Activity的图标设为手机主屏幕上的应用图标,如果它没有图标,就用Application的图标。
第二个名为ShareActivity的组件,能够处理两种隐式Intent,可以接受文本和媒体内容的分享操作,也就是说如果一个隐式Intent能够匹配到任意一个过滤器都可以唤起该Activity。当然,也可以直接通过显示Intent指定启动它。
9. PendingIntent
PendingIntent是对Intent的一种封装。它主要作用在于,让外部的应用执行内部的Intent时候,就好像是在你的应用中还行一样。
通常在以下场景中会使用PendingIntent。
- 当用户点击通知栏时候,才执行的Intent(系统的
NotificationManager
执行的Intent),详情参考这里 - 当用户操作悬浮在主屏幕中的小工具,才执行的Intent(主屏幕应用执行的Intent),详情参考这里
- 在未来某一个特定时间执行的Intent(系统的
AlarmManager
执行的Intent)
因为每一个Intent对象都是针对具体的组件类别(Activity/Service/BroadcastReceiver)进行实例化,因此在创建PendingIntent的时候,也要基于相同的因素去实例化,使用以下方法实例化PendingIntent。
- PendingIntent.getActivity(),返回一个适用于Activity组件的PendingIntent
- PendingIntent.getService(),返回一个适用于Service组件的PendingIntent
- PendingIntent.getBroadcast(),返回一个适用于BroadcastReceiver的PendingIntent
当然官方还有一些其他获取PendingIntent对象的方法,不过内部也是使用上面三个方法来获取实例化对象的。
这三个方法都需要当前应用的context,需要封装的Intent,以及一个或者多个该如何使用该Intent的标志(例如,是否可以多次使用该Intent)。
关于Pending的具体使用也不再这里展开,需要了解具体使用的可以查看Notification中PendingIntent的使用和悬浮工具栏中PendingIntent的使用
10. Intent匹配规则
上文中提到了,当发送一个隐式Intent后,系统会将它与设备中的每一个组件的过滤器进行匹配,匹配属性有
Action
、Category
、Data
三个,需要这三个属性都匹配成功才能唤起相应的组件。10.1 Action匹配规则
一个过滤器可以一个
Action
属性也可以声明多个Action
属性。如下:<intent-filter> <action android:name="android.intent.action.EDIT" /> <action android:name="android.intent.action.VIEW" /> ... </intent-filter>
隐式Intent中的
Action
属性,与组件中的某一个过滤器的Action
能够匹配(如果一个过滤器声明了多个Action
属性,只需要匹配其中一个就行),那么就算是匹配成功。如果过滤器没有声明
Action
属性,那么只有没有设置Action
属性的隐式Intent才能匹配成功。10.2 Category匹配规则
一个过滤器可以不声明
Category
属性也可以声明多个Category
属性,如下:<intent-filter> <category android:name="android.intent.category.DEFAULT" /> <category android:name="android.intent.category.BROWSABLE" /> ... </intent-filter>
隐式Intent中声明的
Category
必须全部能够与某一个过滤器中的Category
匹配才算匹配成功。比如说一个Category
属性设为CATEGORY_BROWSABLE
的隐式Intent也可以通过上面的过滤器,也就是说,过滤器的Category
属性内容必须是大于或者等于隐式Intent的Category
属性时候,隐式Intent才能匹配成功。如果一个隐式Intent没有设置
Category
属性,那么它可以通过任何一个过滤器的Category匹配。10.3 Data匹配规则
一个过滤器可以不声明
Data
属性也可以声明多个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四个部分,host和port合起来也成authority(host:port)部分。<scheme>://<host>:<port>/<path>
例如:
content://192.168.0.1:8080/folder/subfolder/etc
在这个URI中,
scheme
是content,host
是192.168.0.1,port
是8080,path
是folder/subfolder/etc。我们平时使用的网络url就是这种格式。在URI中,每个组成部分都是可选的,但是有线性的依赖关系
- 如果没有
scheme
部分,那么host
部分会被忽略 - 如果没有
host
部分,那么port
部分会被忽略 - 如果
host
部分和port
部分都没有,那么path
部分会被忽略
当进行URI匹配时候,并不是比较全部,而是局部对比,以下是URI匹配规则。
- 如果一个URI仅声明了
scheme
部分,那么所有拥有与其相同的scheme
的URI都会通过匹配,其他部分不做匹配 - 如果一个URI声明了
scheme
部分和authority
部分,那么拥有与其相同scheme
和authority
的URI才能匹配成功,path
部分不做匹配 - 如果一个URI所有的部分都声明了,那么只有所有部分都相同的URI才能匹配成功
注意:
path
部分可以使用通配符(*),也就是path
其中的一部分进行匹配。Data匹配时候,MIME类型和URI两者都会进行匹配,匹配规则如下:
- 如果过滤器未声明URI和MIME类型,则只有不含URI和MIME类型的隐形Intent才能匹配成功
- 如果过滤器中声明URI但是未声明MIME类型(也不能从URI中分析出MIME类型),则只有URI与过滤器URI相同且不包含IME类型的隐式Intent才能匹配成功
- 如果过滤器声明MIME类型但是未声明URI,只有包含相同MIME类型但是不包含URI的隐式Intent才能匹配成功
- 如果过滤器声明了URI和MIME类型(既可以是直接设置,也可以是从URI分析出来),只有包含相同的URI和MIME类型的隐式Intent才能匹配成功
注意:进行匹配时候必须以过滤器为单位进行匹配,不能跨过滤器匹配。如果一个过滤器声明了多个
Action
、Category
、Data
,隐式Intent包含的Action
、Category
、Data
都能在过滤器中匹配到相应的属性即可,也就是说过滤器中声明的属性是大于或者等于Intent中包含的属性,Intent才能匹配成功11. 其他
系统通过过滤器去匹配Intent,启动相应组件,在
PackageManager
类中提供了一系列的查询(queryIntentActivities()/queryIntentServices()/queryBroadcastReceivers())方法去查询可以处理某个Intent的组件,也提供了一系列的解析(resolveActivity()/resolveService())方法来确定最佳启动组件。这些方法在某些场景下是非常有用的,也可以帮助我们降低程序crash风险。12. 思考
上文中对Intent以及IntentFilter进行了详细的讲解,大多都是系统级别的处理过程。但是Intent作为一个官方已经封装好的信息携带者,我们可以用它来做很多事情。比如可以写自己的一套匹配规则,Intent仅仅作为数据携带者,通过它去传递一些信息,实现Fragment/Activity的页面跳转逻辑。关于Intent的使用,我相信还有更多的用处,需要用户一步一步的去探索。
- 启动Activity。Activity可以简单的理解为手机屏幕中的一个页面,你可以通过将Intent传入
-
Intent 和 Intent 过滤器
2017-12-04 14:56:17Intent 和 Intent 过滤器 本文内容 Intent 类型构建 Intent 显式 Intent 示例隐式 Intent 示例强制使用应用选择器 接收隐式 Intent 过滤器示例 使用待定 IntentIntent 解析 操作测试类别...Intent 和 Intent 过滤器
Intent
是一个消息传递对象,您可以使用它从其他应用组件请求操作。尽管 Intent 可以通过多种方式促进组件之间的通信,但其基本用例主要包括以下三个:- 启动 Activity:
Activity
表示应用中的一个屏幕。通过将Intent
传递给startActivity()
,您可以启动新的Activity
实例。Intent
描述了要启动的 Activity,并携带了任何必要的数据。如果您希望在 Activity 完成后收到结果,请调用
startActivityForResult()
。在 Activity 的onActivityResult()
回调中,您的 Activity 将结果作为单独的Intent
对象接收。如需了解详细信息,请参阅 Activity 指南。 - 启动服务:
Service
是一个不使用用户界面而在后台执行操作的组件。通过将Intent
传递给startService()
,您可以启动服务执行一次性操作(例如,下载文件)。Intent
描述了要启动的服务,并携带了任何必要的数据。如果服务旨在使用客户端-服务器接口,则通过将
Intent
传递给bindService()
,您可以从其他组件绑定到此服务。如需了解详细信息,请参阅服务指南。 - 传递广播:
广播是任何应用均可接收的消息。系统将针对系统事件(例如:系统启动或设备开始充电时)传递各种广播。通过将
Intent
传递给sendBroadcast()
、sendOrderedBroadcast()
或sendStickyBroadcast()
,您可以将广播传递给其他应用。
Intent 类型
Intent 分为两种类型:
- 显式 Intent:按名称(完全限定类名)指定要启动的组件。 通常,您会在自己的应用中使用显式 Intent 来启动组件,这是因为您知道要启动的 Activity 或服务的类名。例如,启动新 Activity 以响应用户操作,或者启动服务以在后台下载文件。
- 隐式 Intent :不会指定特定的组件,而是声明要执行的常规操作,从而允许其他应用中的组件来处理它。 例如,如需在地图上向用户显示位置,则可以使用隐式 Intent,请求另一具有此功能的应用在地图上显示指定的位置。
创建显式 Intent 启动 Activity 或服务时,系统将立即启动
Intent
对象中指定的应用组件。图 1. 隐式 Intent 如何通过系统传递以启动其他 Activity 的图解:[1] Activity A 创建包含操作描述的
Intent
,并将其传递给startActivity()
。[2] Android 系统搜索所有应用中与 Intent 匹配的 Intent 过滤器。 找到匹配项之后,[3] 该系统通过调用匹配 Activity(Activity B)的onCreate()
方法并将其传递给Intent
,以此启动匹配 Activity。创建隐式 Intent 时,Android 系统通过将 Intent 的内容与在设备上其他应用的清单文件中声明的 Intent 过滤器进行比较,从而找到要启动的相应组件。 如果 Intent 与 Intent 过滤器匹配,则系统将启动该组件,并向其传递
Intent
对象。 如果多个 Intent 过滤器兼容,则系统会显示一个对话框,支持用户选取要使用的应用。Intent 过滤器是应用清单文件中的一个表达式,它指定该组件要接收的 Intent 类型。 例如,通过为 Activity 声明 Intent 过滤器,您可以使其他应用能够直接使用某一特定类型的 Intent 启动 Activity。同样,如果您没有为 Activity 声明任何 Intent 过滤器,则 Activity 只能通过显式 Intent 启动。
注意:为了确保应用的安全性,启动
Service
时,请始终使用显式 Intent,且不要为服务声明 Intent 过滤器。使用隐式 Intent 启动服务存在安全隐患,因为您无法确定哪些服务将响应 Intent,且用户无法看到哪些服务已启动。从 Android 5.0(API 级别 21)开始,如果使用隐式 Intent 调用bindService()
,系统会引发异常。构建 Intent
Intent
对象携带了 Android 系统用来确定要启动哪个组件的信息(例如,准确的组件名称或应当接收该 Intent 的组件类别),以及收件人组件为了正确执行操作而使用的信息(例如,要采取的操作以及要处理的数据)。Intent
中包含的主要信息如下:- 组件名称
- 要启动的组件名称。
这是可选项,但也是构建显式 Intent 的一项重要信息,这意味着 Intent 应当仅传递给由组件名称定义的应用组件。 如果没有组件名称,则 Intent 是隐式的,且系统将根据其他 Intent 信息(例如,以下所述的操作、数据和类别)决定哪个组件应当接收 Intent。 因此,如需在应用中启动特定的组件,则应指定该组件的名称。
注:启动
Service
时,您应始终指定组件名称。 否则,您无法确定哪项服务会响应 Intent,且用户无法看到哪项服务已启动。Intent
的这一字段是一个ComponentName
对象,您可以使用目标组件的完全限定类名指定此对象,其中包括应用的软件包名称。 例如,com.example.ExampleActivity
。您可以使用setComponent()
、setClass()
、setClassName()
或Intent
构造函数设置组件名称。 - 操作
- 指定要执行的通用操作(例如,“查看”或“选取”)的字符串。
对于广播 Intent,这是指已发生且正在报告的操作。操作在很大程度上决定了其余 Intent 的构成,特别是数据和 extra 中包含的内容。
您可以指定自己的操作,供 Intent 在您的应用内使用(或者供其他应用在您的应用中调用组件)。但是,您通常应该使用由
Intent
类或其他框架类定义的操作常量。以下是一些用于启动 Activity 的常见操作:ACTION_VIEW
- 如果您拥有一些某项 Activity 可向用户显示的信息(例如,要使用图库应用查看的照片;或者要使用地图应用查看的地址),请使用 Intent 将此操作与
startActivity()
结合使用。 ACTION_SEND
- 这也称为“共享”Intent。如果您拥有一些用户可通过其他应用(例如,电子邮件应用或社交共享应用)共享的数据,则应使用 Intent 将此操作与
startActivity()
结合使用。
有关更多定义通用操作的常量,请参阅
Intent
类参考文档。 其他操作在 Android 框架中的其他位置定义。例如,对于在系统的设置应用中打开特定屏幕的操作,将在Settings
中定义。您可以使用
setAction()
或Intent
构造函数为 Intent 指定操作。如果定义自己的操作,请确保将应用的软件包名称作为前缀。 例如:
static final String ACTION_TIMETRAVEL = "com.example.action.TIMETRAVEL";
- 数据
- 引用待操作数据和/或该数据 MIME 类型的 URI(
Uri
对象)。提供的数据类型通常由 Intent 的操作决定。例如,如果操作是ACTION_EDIT
,则数据应包含待编辑文档的 URI。创建 Intent 时,除了指定 URI 以外,指定数据类型(其 MIME 类型)往往也很重要。例如,能够显示图像的 Activity 可能无法播放音频文件,即便 URI 格式十分类似时也是如此。因此,指定数据的 MIME 类型有助于 Android 系统找到接收 Intent 的最佳组件。但有时,MIME 类型可以从 URI 中推断得出,特别当数据是
content:
URI 时尤其如此。这表明数据位于设备中,且由ContentProvider
控制,这使得数据 MIME 类型对系统可见。要仅设置数据 URI,请调用
setData()
。 要仅设置 MIME 类型,请调用setType()
。如有必要,您可以使用setDataAndType()
同时显式设置二者。注意:若要同时设置 URI 和 MIME 类型,请勿调用
setData()
和setType()
,因为它们会互相抵消彼此的值。请始终使用setDataAndType()
同时设置 URI 和 MIME 类型。 - 类别
- 一个包含应处理 Intent 组件类型的附加信息的字符串。 您可以将任意数量的类别描述放入一个 Intent 中,但大多数 Intent 均不需要类别。 以下是一些常见类别:
CATEGORY_BROWSABLE
- 目标 Activity 允许本身通过网络浏览器启动,以显示链接引用的数据,如图像或电子邮件。
CATEGORY_LAUNCHER
- 该 Activity 是任务的初始 Activity,在系统的应用启动器中列出。
有关类别的完整列表,请参阅
Intent
类描述。您可以使用
addCategory()
指定类别。
以上列出的这些属性(组件名称、操作、数据和类别)表示 Intent 的既定特征。 通过读取这些属性,Android 系统能够解析应当启动哪个应用组件。
但是,Intent 也有可能会一些携带不影响其如何解析为应用组件的信息。 Intent 还可以提供:
- Extra
- 携带完成请求操作所需的附加信息的键值对。正如某些操作使用特定类型的数据 URI 一样,有些操作也使用特定的 extra。
您可以使用各种
putExtra()
方法添加 extra 数据,每种方法均接受两个参数:键名和值。您还可以创建一个包含所有 extra 数据的Bundle
对象,然后使用putExtras()
将Bundle
插入Intent
中。例如,使用
ACTION_SEND
创建用于发送电子邮件的 Intent 时,可以使用EXTRA_EMAIL
键指定“目标”收件人,并使用EXTRA_SUBJECT
键指定“主题”。Intent
类将为标准化的数据类型指定多个EXTRA_*
常量。如需声明自己的 extra 键(对于应用接收的 Intent),请确保将应用的软件包名称作为前缀。 例如:static final String EXTRA_GIGAWATTS = "com.example.EXTRA_GIGAWATTS";
- 标志
- 在
Intent
类中定义的、充当 Intent 元数据的标志。 标志可以指示 Android 系统如何启动 Activity(例如,Activity 应属于哪个任务),以及启动之后如何处理(例如,它是否属于最近的 Activity 列表)。如需了解详细信息,请参阅
setFlags()
方法。
显式 Intent 示例
显式 Intent 是指用于启动某个特定应用组件(例如,应用中的某个特定 Activity 或服务)的 Intent。 要创建显式 Intent,请为
Intent
对象定义组件名称 — Intent 的所有其他属性均为可选属性。例如,如果在应用中构建了一个名为
DownloadService
、旨在从网页下载文件的服务,则可使用以下代码启动该服务:// Executed in an Activity, so 'this' is the
Context
// The fileUrl is a string URL, such as "http://www.example.com/image.png" Intent downloadIntent = new Intent(this, DownloadService.class); downloadIntent.setData(Uri.parse
(fileUrl)); startService(downloadIntent);Intent(Context, Class)
构造函数分别为应用和组件提供Context
和Class
对象。因此,此 Intent 将显式启动该应用中的DownloadService
类。如需了解有关构建和启动服务的详细信息,请参阅服务指南。
隐式 Intent 示例
隐式 Intent 指定能够在可以执行相应操作的设备上调用任何应用的操作。 如果您的应用无法执行该操作而其他应用可以,且您希望用户选取要使用的应用,则使用隐式 Intent 非常有用。
例如,如果您希望用户与他人共享您的内容,请使用
ACTION_SEND
操作创建 Intent,并添加指定共享内容的 extra。 使用该 Intent 调用startActivity()
时,用户可以选取共享内容所使用的应用。注意:用户可能没有任何应用处理您发送到
startActivity()
的隐式 Intent。如果出现这种情况,则调用将会失败,且应用会崩溃。要验证 Activity 是否会接收 Intent,请对Intent
对象调用resolveActivity()
。如果结果为非空,则至少有一个应用能够处理该 Intent,且可以安全调用startActivity()
。 如果结果为空,则不应使用该 Intent。如有可能,您应停用发出该 Intent 的功能。// Create the text message with a string Intent sendIntent = new Intent(); sendIntent.setAction(Intent.ACTION_SEND); sendIntent.putExtra(Intent.EXTRA_TEXT, textMessage); sendIntent.setType("text/plain"); // Verify that the intent will resolve to an activity if (sendIntent.resolveActivity(getPackageManager()) != null) { startActivity(sendIntent); }
注:在这种情况下,系统并没有使用 URI,但已声明 Intent 的数据类型,用于指定 extra 携带的内容。
调用
startActivity()
时,系统将检查已安装的所有应用,确定哪些应用能够处理这种 Intent(即:含ACTION_SEND
操作并携带“text/plain”数据的 Intent )。 如果只有一个应用能够处理,则该应用将立即打开并为其提供 Intent。 如果多个 Activity 接受 Intent,则系统将显示一个对话框,使用户能够选取要使用的应用。图 2. 选择器对话框。
强制使用应用选择器
如果有多个应用响应隐式 Intent,则用户可以选择要使用的应用,并将其设置为该操作的默认选项。 如果用户可能希望今后一直使用相同的应用执行某项操作(例如,打开网页时,用户往往倾向于仅使用一种网络浏览器),则这一点十分有用。
但是,如果多个应用可以响应 Intent,且用户可能希望每次使用不同的应用,则应采用显式方式显示选择器对话框。 选择器对话框每次都会要求用户选择用于操作的应用(用户无法为该操作选择默认应用)。 例如,当应用使用
ACTION_SEND
操作执行“共享”时,用户根据目前的状况可能需要使用另一不同的应用,因此应当始终使用选择器对话框,如图 2 中所示。要显示选择器,请使用
createChooser()
创建Intent
,并将其传递给startActivity()
。例如:Intent sendIntent = new Intent(Intent.ACTION_SEND); ... // Always use string resources for UI text. // This says something like "Share this photo with" String title = getResources().getString(R.string.chooser_title); // Create intent to show the chooser dialog Intent chooser = Intent.createChooser(sendIntent, title); // Verify the original intent will resolve to at least one activity if (sendIntent.resolveActivity(getPackageManager()) != null) { startActivity(chooser); }
这将显示一个对话框,其中有响应传递给
createChooser()
方法的 Intent 的应用列表,并且将提供的文本用作对话框标题。接收隐式 Intent
要公布应用可以接收哪些隐式 Intent,请在清单文件中使用
<intent-filter>
元素为每个应用组件声明一个或多个 Intent 过滤器。每个 Intent 过滤器均根据 Intent 的操作、数据和类别指定自身接受的 Intent 类型。 仅当隐式 Intent 可以通过 Intent 过滤器之一传递时,系统才会将该 Intent 传递给应用组件。注:显式 Intent 始终会传递给其目标,无论组件声明的 Intent 过滤器如何均是如此。
应用组件应当为自身可执行的每个独特作业声明单独的过滤器。例如,图像库应用中的一个 Activity 可能会有两个过滤器,分别用于查看图像和编辑图像。 当 Activity 启动时,它将检查
Intent
并根据Intent
中的信息决定具体的行为(例如,是否显示编辑器控件)。每个 Intent 过滤器均由应用清单文件中的
<intent-filter>
元素定义,并嵌套在相应的应用组件(例如,<activity>
元素)中。 在<intent-filter>
内部,您可以使用以下三个元素中的一个或多个指定要接受的 Intent 类型:<action>
- 在
name
属性中,声明接受的 Intent 操作。该值必须是操作的文本字符串值,而不是类常量。 <data>
- 使用一个或多个指定数据 URI 各个方面(
scheme
、host
、port
、path
等)和 MIME 类型的属性,声明接受的数据类型。 <category>
- 在
name
属性中,声明接受的 Intent 类别。该值必须是操作的文本字符串值,而不是类常量。注:为了接收隐式 Intent,必须将
CATEGORY_DEFAULT
类别包括在 Intent 过滤器中。 方法startActivity()
和startActivityForResult()
将按照已申明CATEGORY_DEFAULT
类别的方式处理所有 Intent。 如果未在 Intent 过滤器中声明此类别,则隐式 Intent 不会解析为您的 Activity。
例如,以下是一个使用包含 Intent 过滤器的 Activity 声明,当数据类型为文本时,系统将接收
ACTION_SEND
Intent :<activity android:name="ShareActivity"> <intent-filter> <action android:name="android.intent.action.SEND"/> <category android:name="android.intent.category.DEFAULT"/> <data android:mimeType="text/plain"/> </intent-filter> </activity>
您可以创建一个包括多个
<action>
、<data>
或<category>
实例的过滤器。创建时,仅需确定组件能够处理这些过滤器元素的任何及所有组合即可。如需仅以操作、数据和类别类型的特定组合来处理多种 Intent,则需创建多个 Intent 过滤器。
限制对组件的访问
使用 Intent 过滤器时,无法安全地防止其他应用启动组件。 尽管 Intent 过滤器将组件限制为仅响应特定类型的隐式 Intent,但如果开发者确定您的组件名称,则其他应用有可能通过使用显式 Intent 启动您的应用组件。如果必须确保只有您自己的应用才能启动您的某一组件,请针对该组件将
exported
属性设置为"false"
。系统通过将 Intent 与所有这三个元素进行比较,根据过滤器测试隐式 Intent。 隐式 Intent 若要传递给组件,必须通过所有这三项测试。如果 Intent 甚至无法匹配其中任何一项测试,则 Android 系统不会将其传递给组件。 但是,由于一个组件可能有多个 Intent 过滤器,因此未能通过某一组件过滤器的 Intent 可能会通过另一过滤器。如需了解有关系统如何解析 Intent 的详细信息,请参阅下文的 Intent 解析部分。
注意:为了避免无意中运行不同应用的
Service
,请始终使用显式 Intent 启动您自己的服务,且不必为该服务声明 Intent 过滤器。注:对于所有 Activity,您必须在清单文件中声明 Intent 过滤器。但是,广播接收器的过滤器可以通过调用
registerReceiver()
动态注册。 稍后,您可以使用unregisterReceiver()
注销该接收器。这样一来,应用便可仅在应用运行时的某一指定时间段内侦听特定的广播。过滤器示例
为了更好地了解一些 Intent 过滤器的行为,我们一起来看看从社交共享应用的清单文件中截取的以下片段。
<activity android:name="MainActivity"> <!-- This activity is the main entry, should appear in app launcher --> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <activity android:name="ShareActivity"> <!-- This activity handles "SEND" actions with text data --> <intent-filter> <action android:name="android.intent.action.SEND"/> <category android:name="android.intent.category.DEFAULT"/> <data android:mimeType="text/plain"/> </intent-filter> <!-- This activity also handles "SEND" and "SEND_MULTIPLE" with media data --> <intent-filter> <action android:name="android.intent.action.SEND"/> <action android:name="android.intent.action.SEND_MULTIPLE"/> <category android:name="android.intent.category.DEFAULT"/> <data android:mimeType="application/vnd.google.panorama360+jpg"/> <data android:mimeType="image/*"/> <data android:mimeType="video/*"/> </intent-filter> </activity>
第一个 Activity
MainActivity
是应用的主要入口点。当用户最初使用启动器图标启动应用时,该 Activity 将打开:ACTION_MAIN
操作指示这是主要入口点,且不要求输入任何 Intent 数据。CATEGORY_LAUNCHER
类别指示此 Activity 的图标应放入系统的应用启动器。 如果<activity>
元素未使用icon
指定图标,则系统将使用<application>
元素中的图标。
这两个元素必须配对使用,Activity 才会显示在应用启动器中。
第二个 Activity
ShareActivity
旨在便于共享文本和媒体内容。 尽管用户可以通过从MainActivity
导航进入此 Activity,但也可以从发出隐式 Intent(与两个 Intent 过滤器之一匹配)的另一应用中直接进入ShareActivity
。注:MIME 类型
application/vnd.google.panorama360+jpg
是一个指定全景照片的特殊数据类型,您可以使用 Google panorama API 对其进行处理。使用待定 Intent
PendingIntent
对象是Intent
对象的包装器。PendingIntent
的主要目的是授权外部应用使用包含的Intent
,就像是它从您应用本身的进程中执行的一样。待定 Intent 的主要用例包括:
- 声明用户使用您的通知执行操作时所要执行的 Intent(Android 系统的
NotificationManager
执行Intent
)。 - 声明用户使用您的 应用小部件执行操作时要执行的 Intent(主屏幕应用执行
Intent
)。 - 声明未来某一特定时间要执行的 Intent(Android 系统的
AlarmManager
执行Intent
)。
由于每个
Intent
对象均设计为由特定类型的应用组件(Activity
、Service
或BroadcastReceiver
)进行处理,因此还必须基于相同的考虑因素创建PendingIntent
。使用待定 Intent 时,应用不会使用调用(如startActivity()
)执行该 Intent。相反,通过调用相应的创建器方法创建PendingIntent
时,您必须声明所需的组件类型:PendingIntent.getActivity()
,适用于启动Activity
的Intent
。PendingIntent.getService()
,适用于启动Service
的Intent
。PendingIntent.getBroadcast()
,适用于启动BroadcastReceiver
的Intent
。
除非您的应用正在从其他应用中接收待定 Intent,否则上述用于创建
PendingIntent
的方法可能是您所需的唯一PendingIntent
方法。每种方法均会提取当前的应用
Context
、您要包装的Intent
以及一个或多个指定应如何使用该 Intent 的标志(例如,是否可以多次使用该 Intent)。如需了解有关使用待定 Intent 的详细信息,请参阅通知和应用小部件 API 指南等手册中每个相应用例的相关文档。
Intent 解析
当系统收到隐式 Intent 以启动 Activity 时,它根据以下三个方面将该 Intent 与 Intent 过滤器进行比较,搜索该 Intent 的最佳 Activity:
- Intent 操作
- Intent 数据(URI 和数据类型)
- Intent 类别
下文根据如何在应用的清单文件中声明 Intent 过滤器,描述 Intent 如何与相应的组件匹配。
操作测试
要指定接受的 Intent 操作,Intent 过滤器既可以不声明任何
<action>
元素,也可以声明多个此类元素。例如:<intent-filter> <action android:name="android.intent.action.EDIT" /> <action android:name="android.intent.action.VIEW" /> ... </intent-filter>
要通过此过滤器,您在
Intent
中指定的操作必须与过滤器中列出的某一操作匹配。如果该过滤器未列出任何操作,则 Intent 没有任何匹配项,因此所有 Intent 均无法通过测试。 但是,如果
Intent
未指定操作,则会通过测试(只要过滤器至少包含一个操作)。类别测试
要指定接受的 Intent 类别, Intent 过滤器既可以不声明任何
<category>
元素,也可以声明多个此类元素。 例如:<intent-filter> <category android:name="android.intent.category.DEFAULT" /> <category android:name="android.intent.category.BROWSABLE" /> ... </intent-filter>
若要使 Intent 通过类别测试,则
Intent
中的每个类别均必须与过滤器中的类别匹配。反之则未必然,Intent 过滤器声明的类别可以超出Intent
中指定的数量,且Intent
仍会通过测试。 因此,不含类别的 Intent 应当始终会通过此测试,无论过滤器中声明何种类别均是如此。注:Android 会自动将
CATEGORY_DEFAULT
类别应用于传递给startActivity()
和startActivityForResult()
的所有隐式 Intent。因此,如需 Activity 接收隐式 Intent,则必须将"android.intent.category.DEFAULT"
的类别包括在其 Intent 过滤器中(如上文的<intent-filter>
示例所示)。数据测试
要指定接受的 Intent 数据, Intent 过滤器既可以不声明任何
<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>
例如:
content://com.example.project:200/folder/subfolder/etc
在此 URI 中,架构是
content
,主机是com.example.project
,端口是200
,路径是folder/subfolder/etc
。在
<data>
元素中,上述每个属性均为可选,但存在线性依赖关系:- 如果未指定架构,则会忽略主机。
- 如果未指定主机,则会忽略端口。
- 如果未指定架构和主机,则会忽略路径。
将 Intent 中的 URI 与过滤器中的 URI 规范进行比较时,它仅与过滤器中包含的部分 URI 进行比较。 例如:
- 如果过滤器仅指定架构,则具有该架构的所有 URI 均与该过滤器匹配。
- 如果过滤器指定架构和权限,但未指定路径,则具有相同架构和权限的所有 URI 都会通过过滤器,无论其路径如何均是如此。
- 如果过滤器指定架构、权限和路径,则仅具有相同架构、权限和路径的 URI 才会通过过滤器。
注:路径规范可以包含星号通配符 (*),因此仅需部分匹配路径名即可。
数据测试会将 Intent 中的 URI 和 MIME 类型与过滤器中指定的 URI 和 MIME 类型进行比较。 规则如下:
- 仅当过滤器未指定任何 URI 或 MIME 类型时,不含 URI 和 MIME 类型的 Intent 才会通过测试。
- 对于包含 URI 但不含 MIME 类型(既未显式声明,也无法通过 URI 推断得出)的 Intent,仅当其 URI 与过滤器的 URI 格式匹配、且过滤器同样未指定 MIME 类型时,才会通过测试。
- 仅当过滤器列出相同的 MIME 类型且未指定 URI 格式时,包含 MIME 类型、但不含 URI 的 Intent 才会通过测试。
- 仅当 MIME 类型与过滤器中列出的类型匹配时,同时包含 URI 类型和 MIME 类型(通过显式声明,或可以通过 URI 推断得出)的 Intent 才会通过测试的 MIME 类型部分。 如果 Intent 的 URI 与过滤器中的 URI 匹配,或者如果 Intent 具有
content:
或file:
URI 且过滤器未指定 URI,则 Intent 会通过测试的 URI 部分。 换言之,如果过滤器只是列出 MIME 类型,则假定组件支持content:
和file:
数据。
最后一条规则,即规则 (d),反映了期望组件能够从文件中或内容提供程序获得本地数据。因此,其过滤器可以仅列出数据类型,而不必显式命名
content:
和file:
架构。这是一个典型的案例。 例如,下文中的<data>
元素向 Android 指出,组件可从内容提供商处获得并显示图像数据:<intent-filter> <data android:mimeType="image/*" /> ... </intent-filter>
由于大部分可用数据均由内容提供商分发,因此指定数据类型(而非 URI)的过滤器也许最为常见。
另一常见的配置是具有架构和数据类型的过滤器。例如,下文中的
<data>
元素向 Android 指出,组件可从网络中检索视频数据以执行操作:<intent-filter> <data android:scheme="http" android:type="video/*" /> ... </intent-filter>
Intent 匹配
通过 Intent 过滤器匹配 Intent,这不仅有助于发现要激活的目标组件,还有助于发现设备上组件集的相关信息。 例如,主页应用通过使用指定
ACTION_MAIN
操作和CATEGORY_LAUNCHER
类别的 Intent 过滤器查找所有 Activity,以此填充应用启动器。您的应用可以采用类似的方式使用 Intent 匹配。
PackageManager
提供了一整套query...()
方法来返回所有能够接受特定 Intent 的组件。此外,它还提供了一系列类似的resolve...()
方法来确定响应 Intent 的最佳组件。 例如,queryIntentActivities()
将返回能够执行那些作为参数传递的 Intent 的所有 Activity 列表,而queryIntentServices()
则可返回类似的服务列表。这两种方法均不会激活组件,而只是列出能够响应的组件。 对于广播接收器,有一种类似的方法:queryBroadcastReceivers()
。 - 启动 Activity:
-
android之android.intent.category.DEFAULT的用途和使用
2013-08-18 18:18:501、要弄清楚这个问题,首先需要弄明白什么是implicit(隐藏) intent什么是explicit(明确) intent。 Explicit Intent明确的指定了要启动的Acitivity ,比如以下Java代码: Intent intent= new Intent(this, B.... -
记录:Intent、Intent过滤器和通用Intent
2017-03-13 23:11:30现在可以看中文的部分文档,可是内容真心不好记。看过之后就无名的又忘记了。还是摘抄一道的方式去加深记忆和当做一次笔记方便后面自己快速查找。记录一下,Intent,Intent的过滤和 常用的通用 IntentIntent . . . -
详解显式intent和隐式intent
2018-07-11 18:35:43Intent是Android程序中各组件之间进行交互的一种重要方式。它不仅可以指明activity想要执行的动作,也可以在不同组件之间传输数据。 Intent分为两种,显式intent和隐式intent,以下分别进行描述: 一、显式intent ... -
显式Intent和隐式Intent区别
2017-03-21 13:11:27显式Intent和隐式Intent区别 -
Intent and Intent Filters
2015-05-13 18:16:13意图和意图过滤器意图是一个消息对象你可以从... * 通过startActivity(intent),intent可以携带数据。 * 如果希望在activity结束时接收一个结果,startActivityForResult,你可以在activity的onActivityResult(int req -
Android显式intent和隐式intent
2018-06-11 14:43:34要启动一个Activity有两种方法,一种是通过显式Intent启动,而另一种是通过隐式Intent启动。 一、显示Intent 显示Intent是明确目标Activity的类名。 1、通过Intent(Context packageContext, Class<?&... -
隐式Intent与显示Intent的区别
2018-08-19 17:51:08显式Intent:通过指定Intent组件名称来实现的,它一般用在知道目标组件名称的前提下,去调用Intent.setComponent()、Intent.setClassName()或Intent.setClass()方法或者在new Intent(A.this,B.class)指明需要转向到... -
显示Intent,隐式Intent
2014-03-03 11:22:49Intent 分为两种显示Intent,隐式Intent。 -
Intent的基本知识
2018-09-27 12:31:41我们知道,Intent 是一个消息传递对象,使用它可以向其他Android组件请求操作。Intent的基本用途主要包括:启动 Activity、启动服务、传递广播。Intent分为显式Intent和隐式Intent。下面我通过启动Activity来讲解... -
Intent及其七大属性及intent-filter设置
2019-06-12 17:53:35一、知识点回顾:Activity (一)、如何实现Activity页面...Intent intent = new Intent(MainActivity.this,NextActivity.class); startActivity(intent); //第二种方式: Intent intent = new Intent(); intent.... -
Intent和Intent Filter的区别
2016-05-06 11:37:37在Android 帮助文档中,Intent的介绍为An intent is an abstract description of an operation to be performed,意思是一个Intent是对一个即将进行的操作的抽象,Intent的字面意识就是”意图”,Android应用程序中... -
intent.putExtra与intent.getStringExtra
2017-05-08 09:43:32在当前Activity1使用startActvity(intent)或者startActivityForResult(intent, code)方法跳转到另一个Activity2之前,如果要传递某些String类型数据给Activity2,则会执行: intent.putExtra(String str, String Key)... -
Intent详解
2015-06-05 11:41:21以及Android的三个基本组件——Activity,Service和Broadcast Receiver——都是通过Intent机制激活的,不同类型的组件有不同的传递Intent方式,可以通过我的另一篇博客,Intent和pendingIntent机制详解里有?... -
显示Intent和隐式Intent讲解与实例应用
2018-03-25 14:29:36什么是Intent: Intent是Android中各个组件之间进行交互的一种重要方式 他不仅可以表示当前组件想要执行的步骤,而且还可以在不同组件之间传递数据 Intent的分类 大致分为两种:显性Intent、隐性Intent ... -
Intent 之系统Intent<一>
2016-07-19 21:54:00前言:Android中的Intent中主要有两种:即系统Intent和自定义Intent 系统Intent: 一,基本知识: (1)解释:意图,意图机制,是连接组件的管理者。 (2)Intent对象的基本构成:如:在下雨天,我喜欢吃肉,特别是... -
显式Intent和隐式Intent
2012-09-19 14:41:37对于明确指出了目标组件名称的Intent,我们称之为“显式Intent”。 对于没有明确指出目标组件名称的Intent,则称之为“隐式 Intent”。 对于隐式意图,Android是怎样寻找到这个最合适的组件呢?记的前面我们在... -
一看就懂的 startActivityForResult(Intent intent, int requestCode)
2018-04-17 19:25:36关于startActivityForResult startActivityForResult(Intent intent, int requestCode)老是遗忘 尤其其中的几个参数。老是傻傻分不清。所以今天就简单的记录下来 startActivityForResult startActivityForResult... -
Intent的基本使用
2018-06-19 05:54:54Intent(意图),Android通信的桥梁,比如我们可以通过: startActivity(Intent)/startActivityForResult(Intent):来启动一个Activity startService(Intent)/bindService(Intent):来启动一个Service ... -
显示Intent和隐式Intent的区别
2015-11-12 07:56:10显示Intent和隐式Intent的区别 1:都是用来在一个activity中启动另外一个activity 2:显示Intent直接指明要启动activity的定义,即activity.class;隐式intent通过在androidmanifest.xml配置action来隐式的启动... -
Android Intent and Intent Filter
2010-05-10 20:26:00Intents and Intent Filters Intent Objects Intent对象 Intent Resolution Intent解析 Intent filtersFilters and security Filter和安全 Common cases 常见情况 Using intent matching 使用intent匹配Note Pa -
Android Intent和Intent Filter介绍
2013-05-26 13:47:39...本文主要介绍Intent和Intent Filter的概念及作用、Intent的结构、两种类型Intent、 Intent和Intent Filter 的匹配规则、利用Intent调用其他常见程序。 1、Intent和Intent Filter -
Intent过滤器
2016-04-29 08:38:06隐式启动Activity时,并没有在Intent中指明Acitivity所在的类,因此,Android系统一定存在某种匹配机制,使Android系统能够根据Intent中的数据信息,找到需要启动的Activity。这种匹配机制是依靠Android系统中的... -
Intent intent =new Intent(getActivity(),DeliverListActivity.class,Cannot resolve method'getActivity'
2019-06-17 13:29:13Android 开发遇到的问题: ...Intent intent =new Intent(getActivity(),DeliverListActivity.class); startActivity(intent); 遇到问题:Cannot resolve method’getActivity’ 解决这个问题首先要查看一下app–&g... -
Android之Intent详解
2019-01-20 00:18:051.Intent的作用?都有哪些属性? Intent是应用程序种各个组件联系的桥梁,通信的载体,负责应用程序中数据的传递(运输大队长) 启动一个Acitivity: Context.this.startActivity(intent); 启动一个Sercvie ...
-
办公软件 - 华为mate pro浏览器允许安装
-
pyinstaller:打包发布icon不成功问题
-
SSM三大框架整合详细教程(SPRING+SPRINGMVC+MYBATIS)
-
【数据分析-随到随学】数据分析建模和预测
-
力扣 leetcode 989. 数组形式的整数加法 (python)
-
three.js入门速成
-
day89-谈应用的性能优化
-
电子书籍阅读网页模板
-
阿里云云计算ACP考试必备教程
-
往事如烟 - 父亲母亲的居木子豆腐
-
【数据分析-随到随学】数据分析基础及方法论
-
Swoole扩展安装教程
-
linux 服务器系统 命令配制与lamp网站搭建环境配制
-
ubantu18.04 安装docker
-
2021-01-22
-
旅游信息服务门户网页模板
-
单片机完全学习课程全五季套餐
-
mac_navicat_mongodb.zip
-
如果面试官再考在无序数组中找第K小的值,就用这篇文章跟他唠!
-
python函数入门和使用