【转】Pro Android学习笔记(十二):了解Intent(下)
解析Intent,寻找匹配Activity
如果给出component名字(包名、类名)是explicit intent,否则是implicit intent。对于explicit intent,关键就是component 名字,在<intent-fliter>中声明的其他属性被忽略。对于implicit intent,则根据action,category和data来进行匹配。然而一个intent fliter中可以声明多个actions,多个categories,多个data属性,因此可以满足不同的intent。
对于implicit intent设置了action,则该action必须存在于<intent-fliter>之下的某个<action nandroid:name=”……”>。但是和《Pro Android 4.0》所写的不一样,经过测试,我们发现intent-fliter下必须存在action的声明。
1)对于设置了action的intent,不能匹配intent-fliter下没有定义action的情况;
2)对于没有设置action的intent,也不能匹配intent-fliter下没有定义action的情况;
3)对于没有设置action的intent,可以匹配intent-fliter下任何定义的action,但是intent应提供足够的过滤条件,例如data的Uri(测试显示使用category过滤不能匹配)。
至少在Android 4.2版本下的测试如是。因此,我们应该在inter-fliter中声明action name,intent应该提供action name,如特殊情况不能提供,需要提供data属性进行过滤。但这种特殊情况不应该出现,换言之,我们必须做到action匹配。
如果implicit intent设置了data schema,必须能与intent fliter某个data schema匹配;如果intent fliter下设置了data schema,implicit intent必须提供有效的data URI,不能为空。对于URI,除了schema外,还可以对authority(即domain)有要求,在manifest中定义为如下。
<data android:scheme="wei" android:host="flowingflying.com"/>
匹配Uri为:wei://flowingflying.com/….,还可以通过android:path,android:pathPrefix,android:pathpattern做进一步限制,具体可以查看http://developer.android.com/guide/topics/manifest/data-element.htm。
同样,对于data mimetype,也必须双方进行匹配,不存在不能视为匹配。通过setType()进行设置,如intent.setType(“text/html”);此外,对于subType,可以用*作为通配,例如intent.setType(“text/*”);
ACTION_PICK
Activity A通过intent唤起Activity B,在某种情况下,我们希望B在结束时能换回信息给A以便A确定下一步的处理工作,这同时也是利用B作为UI的一种方式。一种常用的方式是B是list列表的UI,下面是一个小例子,我们不具体实现B的list UI,只是模拟选择item后设置返回值和返回信息,返回信息由Intent进行携带,本例将自动关闭B。
Activity B步骤1:在AndriodManifest.xml中B的intent fliter中增设PICK的action
<activity …… >
<intent-filter>
… …
<data android:scheme="wei" />
<action android:name="android.intent.action.PICK" />
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</activity>
Activity B步骤2:在B中设置返回值和返回信息,本例返回信息模拟一个NotePad的Uri,并自动关闭B
......
private void testPick(int itemIndex){
//由于intent fliter可以带有多个action,需要先过滤,只有PICK的action才进行返回值操作
if(Intent.ACTION_PICK.equals(this.getIntent().getAction())){
//设置返回值RESULT_OK,并同时通过intent携带信息传递,本例通过data传递Uri
setResult(Activity.RESULT_OK /*返回值*/,
new Intent().setData(getNoteUri(itemIndex))/*携带信息的intent*/);
//自动关闭Activity B,只有B结束时,返回值才传递给A。当然也可以手工结束B,如按系统返回键。
finish();
}
}
private Uri getNoteUri(int itemIndex){
return Uri.parse("content://com.google.provider.NotePad/notes/" + itemIndex);
}
Activity A:
private static final int PICK_REQUEST_CODE = 1000;
private void invokePick(Activity activity){
//设置唤起B的intent,action为PICK,本例中的setData只是为implicit的匹配
Intent intent = new Intent(Intent.ACTION_PICK);
intent.setData(Uri.parse("wei://flowingflying.com/notes"));
//不使用startActivity,因为startActivity类似开启一个modal dialog,无法进行callBack,因此采用startActivityForResult()
activity.startActivityForResult(intent, PICK_REQUEST_CODE /*request code*/);//由于可以PICK方式唤起多个不同的Activity,所有的callBack都触发onActivityResult()方法,采用request code用于进行区分。
}
//下面是重写Activity的onActivityResult()方法,当B结束时被触发,其中第一个参数requestCode为startActivityForResult()中所携带的,可以判断是从那个Activity中返回;第二个参数是B的返回值,有系统值RESULT_OK(-1)、RESULT_CANCELED(1),或者用户自定义值,自定义值必须从RESULT_FIRST_USER(1)开始;第三个参数是B通过intent携带的返回信息
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent outputIntent) {
// TODO Auto-generated method stub
super.onActivityResult(requestCode, resultCode, outputIntent);
//本例只处理Activity B的返回情况,其request code为PICK_REQUEST_CODE){
if(requestCode != PICK_REQUEST_CODE){
Log.d("WEI","Some one else called this. not us");
return;
}
//如果返回值非OK,即RESULT_CANCELED,不处理
if(resultCode != Activity.RESULT_OK){
Log.d("WEI","Result is not OK");
return;
}
//读intent携带的信息
Uri uri = outputIntent.getData();
Log.d("WEI","uri is " + uri.toString());
//根据携带信息进行处理:本例B返回一个NotePad的content Uri,用之打开NotePad。NotePad在模拟器上是没有的,我们可以通过sample进行导入,具体参见本博最后的附
startActivity(new Intent(Intent.ACTION_EDIT,uri));
}
ACTION_GET_CONTENT
ACTION_GET_CONTENT和ACTION_PICK非常相似,ACTION_PICK是给出URI,系统给出一个或者多个匹配的选择给用户,执行后,唤起的Activity返回值给唤起方。 而ACTION_CET_CONTENT不是基于URI,而是根据MIME Type。
本例使用NotePad,请参考本博最后的附:为模拟器安装NotePad。我们先看看sample NotePad的Manifest.xml文件。该文件展现了多个intent-fliter共存的情况,分别针对应用启动,PICK唤起和GET_CONTENT唤起三种情况。
<activity android:name="NotesList" android:label="@string/title_notes_list">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<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>
<intent-filter>
<action android:name="android.intent.action.GET_CONTENT" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="vnd.android.cursor.item/vnd.google.note" />
</intent-filter>
</activity>
代码编写和PICK相似:
private static final int REQUEST_CODE_GET_CONTENT = 101;
private void invokeGetContent(Activity activity){
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.setType("vnd.android.cursor.item/vnd.google.note"); //GET_CONTENT针对MIME TYPE
activity.startActivityForResult(intent, REQUEST_CODE_GET_CONTENT);
}
@Override //接收Acivity的返回信息
protected void onActivityResult(int requestCode, int resultCode, Intent outputIntent) {
if(resultCode != Activity.RESULT_OK){
Log.d("Wei","Result is not OK");
return;
}
switch(requestCode){
case REQUEST_CODE_PICK:
…… //对ACTION_PICK的处理,参考上一例子
break;
case REQUEST_CODE_GET_CONTENT:
Uri uriContent = outputIntent.getData();
Log.d("Wei","uri is " + uriContent.toString());
startActivity(new Intent(Intent.ACTION_EDIT,uriContent));
break;
default:
showInfo("Some one else called this. not us");
break;
}
}
Pending Intent
Intent可以作为PendingIntent中的一个参数。PengdingIntent,顾名思义,不是马上调用的,可以在某个事件触发后才唤起。例如在通知中使用,得到用户点击通知时才调起,见Android学习笔记(五四):通知Notification(上);又例如警告,如地理位置匹配时调起,见Android学习笔记(五六):位置Location。即时唤起方进程(应用)已经不存在,PendingIntent仍得以很好地保存,很方便进程结束后或其他进程调用。
我们做个小实验,看看PendingIntent如何建立:
public static PendingIntent getActivity (Context context, int requestCode, Intent intent, int flags)
public static PendingIntent getActivities (Context context, int requestCode, Intent[] intents, int flags)
Intent intent = new Intent(this,IntentBasicViewActivity.class); //普通的intent
PendingIntent pi = PendingIntent.getActivity(getApplicationContext(),0,intent,0);
showInfo("intent is " + intent); //showInfo()同时在LogCat和UI窗口中显示
showInfo("pending intent is " + pi);
PendingIntent pi1 = PendingIntent.getActivity(getApplicationContext(),0,intent,0);
showInfo("pending intent is " + pi1);
PendingIntent pi2 = PendingIntent.getActivity(getApplicationContext(),1,intent,0);
showInfo("pending intent is " + pi2);
为何使用getActivity如此奇特的方式。普通的intent可以通过startActivity(intent),startService(intent)和sendBroadcast(intent)来唤起Activity,开启服务和唤起broadcast receiver。由于最终要通过PendingIntent中的intent参数实际去唤起对应的Activity、服务或广播接收器,需要告之系统到底是Activity、服务还是广播。相应的也会有:
getBroadcast(Context context, int requestCode, Intent intent, int flags)
getService(Context context, int requestCode, Intent intent, int flags)
至于为何用getxxxx这种方式,据《Pro Android 4.0》是这样解释:Android会存储PendingIntent,并可以多次重用(具体取决于flag参数的设置),如果需要使用相同的intent,需要获得相同的PendingIntent,所有用get。如果要进行区分,则可设置不同的requestCode。
对于flag参数,有:
【1】FLAG_CANCEL_CURRENT:如果当前系统中已经存在一个相同的PendingIntent对象,那么就将先将已有的PendingIntent取消,然后重新生成一个PendingIntent对象。
【2】FLAG_NO_CREATE:如果当前系统中不存在相同的PendingIntent对象,系统将不会创建该PendingIntent对象而是直接返回null。
【3】FLAG_ONE_SHOT:该PendingIntent只作用一次。在该PendingIntent对象通过send()方法触发过后,PendingIntent将自动调用cancel()进行销毁,那么如果你再调用send()方法的话,系统将会返回一个SendIntentException。
【4】FLAG_UPDATE_CURRENT:如果系统中有一个和你描述的PendingIntent对等的PendingInent,那么系统将使用该PendingIntent对象,但是会使用新的Intent来更新之前PendingIntent中的Intent对象数据,例如更新Intent中的Extras。
【说明】这是其中几个flag的解释,参考自http://blog.csdn.net/hudashi/article/details/7060837,更多的请阅读http://developer.android.com/reference/android/app/PendingIntent.html#FLAG_CANCEL_CURRENT
如果我们获得一个PendingIntent,要唤起当中的Intent,可以使用
pi.send(RESULT_CODE); //PendingInten多个send方法
附:为模拟器安装NotePad
从Android SDK Manager上下载sample代码,然后根据下图的操作将之加入模拟器。
为了在PICK和GET_CONTENT调用中有更好的用户体验,当用户选择了item后,NotePad activity能够自动关闭。我们在NotesList.java中加入以下一行代码:
protected void onListItemClick(ListView l, View v, int position, long id) {
……
// Handles requests for note data
if (Intent.ACTION_PICK.equals(action) || Intent.ACTION_GET_CONTENT.equals(action)) {
// Sets the result to return to the component that called this Activity.
// result contains the new URI
setResult(RESULT_OK, new Intent().setData(uri));
//Wei Add the following: close NoteList automatically
finish(); //wei Add
……
}
相关链接: 我的Android开发相关文章
转自http://blog.csdn.net/flowingflying/article/details/9384389
【转】Pro Android学习笔记(十二):了解Intent(下)的更多相关文章
- 【转】 Pro Android学习笔记(二二):用户界面和控制(10):自定义Adapter
目录(?)[-] 设计Adapter的布局 代码部分 Activity的代码 MyAdapter的代码数据源和构造函数 MyAdapter的代码实现自定义的adapter MyAdapter的代码继续 ...
- 【转】Pro Android学习笔记(二五):用户界面和控制(13):LinearLayout和TableLayout
目录(?)[-] 布局Layout 线性布局LinearLayout 表格布局TableLayout 布局Layout Layout是容器,用于对所包含的view进行布局.layout是view的子类 ...
- 【转】 Pro Android学习笔记(二九):用户界面和控制(17):include和merge
目录(?)[-] xml控件代码重用include xml控件代码重用merge 横屏和竖屏landsacpe portrait xml控件代码重用:include 如果我们定义一个控件,需要在不同的 ...
- 【转】Pro Android学习笔记(二):开发环境:基础概念、连接真实设备、生命周期
在Android学习笔记(二):安装环境中已经有相应的内容.看看何为新.这是在source网站上的Android架构图,和标准图没有区别,只是这张图颜色好看多了,录之.本笔记主要讲述Android开发 ...
- 【转】 Pro Android学习笔记(二十):用户界面和控制(8):GridView和Spinner
目录(?)[-] GridView Spinner GridView GridView是网格状布局,如图所示.在了解ListView后,很容易了解GridView.下面是例子的XML文件. <? ...
- 【转】 Pro Android学习笔记(二一):用户界面和控制(9):Gallery和SimpleAdapter
Gallery画廊式控件,如图所示,但是在API level 16,也即Android 4.1,被deprecated,可以使用HorizontableScroolView和ViewPager.但是后 ...
- 【转】Pro Android学习笔记(二六):用户界面和控制(14):RelativeLayout
相对布局:RelativeLayout RelativeLayout也是非常常用的布局,能够精确对控件的位置进行网格对齐,可以设置在控件与其他控件的相对位置,以及控件在容器中的位置.缺省控件的位置为最 ...
- 【转】Pro Android学习笔记(二四):用户界面和控制(12):Style和Theme
目录(?)[-] 静态格式 代码中设定 Style Theme 静态格式 在res/values中设置静态的Style,在资源中设置静态Style可使用的HTML格式有<i> <u& ...
- 【转】 Pro Android学习笔记(五二):ActionBar(5):list模式
可以在action bar中加入spinner的下来菜单,有关spinner,可以参考Pro Android学习笔记(二十):用户界面和控制(8):GridView和Spinner. list的样式和 ...
- 【转】Pro Android学习笔记(三十):Menu(1):了解Menu
目录(?)[-] 创建Menu MenuItem的属性itemId MenuItem的属性groupId MenuItem的属性orderId MenuItem的属性可选属性 Menu触发 onOpt ...
随机推荐
- 【python】-- 基于Django的杂货铺
Django的杂货铺 此篇文章保存基于Django而实现的各种小功能示例 1.验证码 + Session 这个是在前端图片验证码的生成,再配合Session进行后端校验的功能示例 import ran ...
- Delphi 对话框实现源码分析
Delphi 对话框实现源码分析 简介 在这篇文章中,我将大概的从Delphi XE2 的Dialogs单元入手,分析ShowMessage,MessageBox等对话框运行原理,希望能帮助你理解 ...
- 我的Android进阶之旅------>如何将Android源码导入Eclipse中来查看(非常实用)
Android源码下载完成的目录结构如如所示: step1:将.classpath文件拷贝到源代码的根目录 Android源码支持多种IDE,如果是针对APP层做开发的话,建议大家使用Eclipse开 ...
- Ubuntu 13.04 可以使用的源
以下为收集的Ubuntu 13.04 可以使用的源 #中科大源deb http://mirrors.ustc.edu.cn/ubuntu/ saucy main restricted universe ...
- Data Structure Linked List: Reverse a Linked List in groups of given size
http://www.geeksforgeeks.org/reverse-a-list-in-groups-of-given-size/ #include <iostream> #incl ...
- iOS中成员变量和属性区别
历史由来: 接触iOS的人都知道,@property声明的属性默认会生成一个_类型的成员变量,同时也会生成setter/getter方法. 但这只是在iOS5之后,苹果推出的一个新机制.看老代码时,经 ...
- 【leetcode刷题笔记】Substring with Concatenation of All Words
You are given a string, S, and a list of words, L, that are all of the same length. Find all startin ...
- P3506 [POI2010]MOT-Monotonicity 2
题目 P3506 [POI2010]MOT-Monotonicity 2 第一次切掉没题解的题\(qwq\) 做法 首先确定\(a_i\)的位置后显然就能确定\(a_{i+1}\)的位置,建一棵权值线 ...
- 导出数据到表格PHP
导出数据到表格 public function excel(){ $filename = '导出表格'; $header = ['编号','名称']; $index = ['id','name']; ...
- 20145229吴姗珊 《Java程序设计》第6周学习总结
20145229吴姗珊 <Java程序设计>第6周学习总结 教材学习内容总结 第十章 输入\输出 1.java将输入\输出抽象化为串流,数据有来源及目的地,衔接两者的是串流对象 2.输入串 ...