Android中的Intent对象完全解析
一、Intent作用
Intent是一个将要执行的动作的抽象的描述,一般来说是作为参数来使用,由Intent来协助完成Android各个组件之间的通讯。比如说调用startActivity()来启动一个activity,或者由broadcaseIntent()来传递给所有感兴趣的BroadcaseReceiver,再或者由startService()/bindservice()来启动一个后台的service.所以可以看出来,intent主要是用来启动其他的activity或者service,所以可以将intent理解成activity之间的粘合剂。
二、Intent的构成
要在不同的activity之间传递数据,就要在intent中包含相应的东西,一般来说数据中最基本的应该包括:
Action用来指明要实施的动作是什么,比如说ACTION_VIEW,ACTION_EDIT等。具体的可以查阅androidSDK->reference中的Android.content.intent类,里面的constants中定义了所有的action。
Data要事实的具体的数据,一般由一个Uri变量来表示
下面是一些简单的例子:
ACTION_VIEWcontent://contacts/1//显示identifier为1的联系人的信息。 ACTION_DIALcontent://contacts/1//给这个联系人打电话
除了Action和data这两个最基本的元素外,intent还包括一些其他的元素,
Category(类别):这个选项指定了将要执行的这个action的其他一些额外的信息,例如LAUNCHER_CATEGORY表示Intent的接受者应该在Launcher中作为顶级应用出现;而ALTERNATIVE_CATEGORY表示当前的Intent是一系列的可选动作中的一个,这些动作可以在同一块数据上执行。具体同样可以参考androidSDK->reference中的Android.content.intent类。以前我也写过一篇于category有关的文章,点击这里可以查看。
Type(数据类型):显式指定Intent的数据类型(MIME)。一般Intent的数据类型能够根据数据本身进行判定,但是通过设置这个属性,可以强制采用显式指定的类型而不再进行推导。
component(组件):指定Intent的的目标组件的类名称。通常Android会根据Intent中包含的其它属性的信息,比如action、data/type、category进行查找,最终找到一个与之匹配的目标组件。但是,如果component这个属性有指定的话,将直接使用它指定的组件,而不再执行上述查找过程。指定了这个属性以后,Intent的其它所有属性都是可选的。
extras(附加信息),是其它所有附加信息的集合。使用extras可以为组件提供扩展信息,比如,如果要执行“发送电子邮件”这个动作,可以将电子邮件的标题、正文等保存在extras里,传给电子邮件发送组件。
下面是这些额外属性的几个例子:
ACTION_MAINwithcategoryCATEGORY_HOME//用来Launchhomescreen.以前我也写过一篇于与之有关的文章,点击这里可以看到。
ACTION_GET_CONTENTwithMIMEtypevnd.android.cursor.item/phone//用来列出列表中的所有人的电话号码
综上可以看出,action、data/type、category和extras一起形成了一种语言,这种语言可以是android可以表达出诸如“给张三打电话”之类的短语组合。
三、intent的解析
应用程序的组件为了告诉Android自己能响应、处理哪些隐式Intent请求,可以声明一个甚至多个IntentFilter。每个IntentFilter描述该组件所能响应Intent请求的能力——组件希望接收什么类型的请求行为,什么类型的请求数据。比如之前请求网页浏览器这个例子中,网页浏览器程序的IntentFilter就应该声明它所希望接收的IntentAction是WEB_SEARCH_ACTION,以及与之相关的请求数据是网页地址URI格式。如何为组件声明自己的IntentFilter?常见的方法是在AndroidManifest.xml文件中用属性<Intent-Filter>描述组件的IntentFilter。
前面我们提到,隐式Intent(ExplicitIntents)和IntentFilter(ImplicitIntents)进行比较时的三要素是Intent的动作、数据以及类别。实际上,一个隐式Intent请求要能够传递给目标组件,必要通过这三个方面的检查。如果任何一方面不匹配,Android都不会将该隐式Intent传递给目标组件。接下来我们讲解这三方面检查的具体规则。
1.动作测试
<intent-filter>元素中可以包括子元素<action>,比如:
<intent-filter> <actionandroid:name=”com.example.project.SHOW_CURRENT”/> <actionandroid:name=”com.example.project.SHOW_RECENT”/> <actionandroid:name=”com.example.project.SHOW_PENDING”/> </intent-filter>
一条<intent-filter>元素至少应该包含一个<action>,否则任何Intent请求都不能和该<intent-filter>匹配。如果Intent请求的Action和<intent-filter>中个某一条<action>匹配,那么该Intent就通过了这条<intent-filter>的动作测试。如果Intent请求或<intent-filter>中没有说明具体的Action类型,那么会出现下面两种情况。
(1)如果<intent-filter>中没有包含任何Action类型,那么无论什么Intent请求都无法和这条<intent-filter>匹配;
(2)反之,如果Intent请求中没有设定Action类型,那么只要<intent-filter>中包含有Action类型,这个Intent请求就将顺利地通过<intent-filter>的行为测试。
2.类别测试
<intent-filter>元素可以包含<category>子元素,比如:
<intent-filter...> <categoryandroid:name=”android.Intent.Category.DEFAULT”/> <categoryandroid:name=”android.Intent.Category.BROWSABLE”/> </intent-filter>
只有当Intent请求中所有的Category与组件中某一个IntentFilter的<category>完全匹配时,才会让该Intent请求通过测试,IntentFilter中多余的<category>声明并不会导致匹配失败。一个没有指定任何类别测试的IntentFilter仅仅只会匹配没有设置类别的Intent请求。
3.数据测试
数据在<intent-filter>中的描述如下:
<intent-filter...> <dataandroid:type=”video/mpeg”android:scheme=”http”.../> <dataandroid:type=”audio/mpeg”android:scheme=”http”.../> </intent-filter>
元素指定了希望接受的Intent请求的数据URI和数据类型,URI被分成三部分来进行匹配:scheme、authority和path。其中,用setData()设定的Inteat请求的URI数据类型和scheme必须与IntentFilter中所指定的一致。若IntentFilter中还指定了authority或path,它们也需要相匹配才会通过测试。
4.简单例子说明
讲解完Intent基本概念之后,接下来我们就使用Intent激活Android自带的电话拨号程序,通过这个实例你会发现,使用Intent并不像其概念描述得那样难。最终创建Intent的代码如下所示。
Intenti=new Intent(Intent.ACTION_DIAL,Uri.parse(”tel://13800138000″));
创建好Intent之后,你就可以通过它告诉Android希望启动新的Activity了。
startActivity(i);
Activity启动后显示界面如下:
三、Intent的构造函数
公共构造函数:
1、Intent()空构造函数
2、Intent(Intento)拷贝构造函数
3、Intent(Stringaction)指定action类型的构造函数
4、Intent(Stringaction,Uriuri)指定Action类型和Uri的构造函数,URI主要是结合程序之间的数据共享ContentProvider
5、Intent(ContextpackageContext,Class<?>cls)传入组件的构造函数,也就是上文提到的
6、Intent(Stringaction,Uriuri,ContextpackageContext,Class<?>cls)前两种结合体
Intent有六种构造函数,3、4、5是最常用的,并不是其他没用!
Intent(Stringaction,Uriuri) 的action就是对应在AndroidMainfest.xml中的action节点的name属性值。在Intent类中定义了很多的Action和Category常量。
示例代码二:
Intentintent=newIntent(Intent.ACTION_EDIT,null); startActivity(intent);
示例代码二是用了第四种构造函数,只是uri参数为null。执行此代码的时候,系统就会在程序主配置文件AndroidMainfest.xml中寻找<actionandroid:name="android.intent.action.EDIT"/>对应的Activity,如果对应为多个activity具有<actionandroid:name="android.intent.action.EDIT"/>此时就会弹出一个dailog选择Activity。
如果是用示例代码一那种方式进行发送则不会有这种情况。
利用Intent在Activity之间传递数据
在Main中执行如下代码:
Bundlebundle=newBundle(); bundle.putStringArray("NAMEARR",nameArr); Intentintent=newIntent(Main.this,CountList.class); intent.putExtras(bundle); startActivity(intent);
在CountList中,代码如下:
Bundlebundle=this.getIntent().getExtras(); String[]arrName=bundle.getStringArray("NAMEARR");
以上代码就实现了Activity之间的数据传递!
四、常用方法总结
这篇文章是我刚开始学习Android时看到的,当时理解的不是很深入,现在再回头看这篇文章总结的很详细,在这里与大家分享。
1,调用web浏览器
UrimyBlogUri=Uri.parse("http://kuikui.javaeye.com"); returnIt=newIntent(Intent.ACTION_VIEW,myBlogUri);
2,地图
UrimapUri=Uri.parse("geo:38.899533,-77.036476"); returnIt=newIntent(Intent.ACTION_VIEW,mapUri);
3,调拨打电话界面
UritelUri=Uri.parse("tel:100861"); returnIt=newIntent(Intent.ACTION_DIAL,telUri);
4,直接拨打电话
UricallUri=Uri.parse("tel:100861"); returnIt=newIntent(Intent.ACTION_CALL,callUri);
5,卸载
UriuninstallUri=Uri.fromParts("package","xxx",null); returnIt=newIntent(Intent.ACTION_DELETE,uninstallUri);
6,安装
UriinstallUri=Uri.fromParts("package","xxx",null); returnIt=newIntent(Intent.ACTION_PACKAGE_ADDED,installUri);
7,播放
UriplayUri=Uri.parse("file:///sdcard/download/everything.mp3"); returnIt=newIntent(Intent.ACTION_VIEW,playUri);
8,调用发邮件
UriemailUri=Uri.parse("mailto:shenrenkui@gmail.com"); returnIt=newIntent(Intent.ACTION_SENDTO,emailUri);
9,发邮件
returnIt=newIntent(Intent.ACTION_SEND); String[]tos={"shenrenkui@gmail.com"}; String[]ccs={"shenrenkui@gmail.com"}; returnIt.putExtra(Intent.EXTRA_EMAIL,tos); returnIt.putExtra(Intent.EXTRA_CC,ccs); returnIt.putExtra(Intent.EXTRA_TEXT,"body"); returnIt.putExtra(Intent.EXTRA_SUBJECT,"subject"); returnIt.setType("message/rfc882"); Intent.createChooser(returnIt,"ChooseEmailClient");
10,发短信
UrismsUri=Uri.parse("tel:100861"); returnIt=newIntent(Intent.ACTION_VIEW,smsUri); returnIt.putExtra("sms_body","shenrenkui"); returnIt.setType("vnd.android-dir/mms-sms");
11,直接发邮件
UrismsToUri=Uri.parse("smsto://100861"); returnIt=newIntent(Intent.ACTION_SENDTO,smsToUri); returnIt.putExtra("sms_body","shenrenkui");
12,发彩信
UrimmsUri=Uri.parse("content://media/external/images/media/23"); returnIt=newIntent(Intent.ACTION_SEND); returnIt.putExtra("sms_body","shenrenkui"); returnIt.putExtra(Intent.EXTRA_STREAM,mmsUri); returnIt.setType("image/png");
用获取到的Intent直接调用startActivity(returnIt)就ok了。
五、eg:
<RelativeLayoutxmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" tools:context=".MainActivity"> <Button android:id="@+id/button1" android:layout_height="wrap_content" android:layout_width="match_parent" android:text="启动第二个Activity"/> </RelativeLayout>
<?xmlversion="1.0"encoding="utf-8"?> <LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <TextView android:id="@+id/text1" android:layout_width="match_parent" android:layout_height="wrap_content" /> </LinearLayout>
packagecom.android.xiong.intent_one; importandroid.os.Bundle; importandroid.app.Activity; importandroid.content.Intent; importandroid.view.Menu; importandroid.view.View; importandroid.view.View.OnClickListener; importandroid.widget.Button; publicclassMainActivityextendsActivity{ privateButtonbutton1; @Override protectedvoidonCreate(BundlesavedInstanceState){ super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); button1=(Button)findViewById(R.id.button1); OnClickon=newOnClick(); button1.setOnClickListener(on); } classOnClickimplementsOnClickListener{ @Override publicvoidonClick(Viewarg0){ //TODOAuto-generatedmethodstub Intentintent=newIntent(); intent.setClass(MainActivity.this,TwoActivity.class); String[]name={"zhangsan","lis","wangwu"}; int[]age={12,13,14}; intent.putExtra("com.android.xiong.intent_one.Name",name); intent.putExtra("com.android.xiong.intent_one.Age",age); startActivity(intent); } } @Override publicbooleanonCreateOptionsMenu(Menumenu){ //Inflatethemenu;thisaddsitemstotheactionbarifitispresent. getMenuInflater().inflate(R.menu.main,menu); returntrue; } }
packagecom.android.xiong.intent_one; importjava.util.HashMap; importandroid.app.Activity; importandroid.content.Intent; importandroid.os.Bundle; importandroid.widget.TextView; publicclassTwoActivityextendsActivity{ privateTextViewtext1; @Override protectedvoidonCreate(BundlesavedInstanceState){ //TODOAuto-generatedmethodstub super.onCreate(savedInstanceState); setContentView(R.layout.activity_two); text1=(TextView)findViewById(R.id.text1); Intentintent=getIntent(); String[]name=intent.getStringArrayExtra("com.android.xiong.intent_one.Name"); int[]age=intent.getIntArrayExtra("com.android.xiong.intent_one.Age"); Stringprint=""; for(inti=0;i<age.length;i++){ print+="name:"+name[i].toString()+"age:"+age[i]+"\n"; } text1.setText(print); } }