Android2.1--UI基本控件<3>--初学者对Intent的理解
Intent是Activity之间的桥梁,一个Activity与另一个Activity之间的跳转是由Intent联系的,
1、什么是Intent?
Intent是一种运行时绑定(runtime binding)机制,它能在程序运行的过程中连接两个不同的组件。通过Intent,你的程序可以向Android表达某种请求或者意愿,Android会根据意愿的内容选择适当的组件(例如,activity)来响应。比如,有一个Activity希望打开网页浏览器查看某一网页的内容,那么这个Activity只需要发出设置WEB_SEARCH_ACTION的Intent请求给Android,Android 会根据Intent的内容,查询各组件注册时的声明的IntentFilter,找到网页浏览器Activity来浏览网页。
2、Android如何解析Intent?
在应用中,我们可以以两种形式来使用Intent:
直接Intent:指定了component属性的Intent(调用setComponent(ComponentName)或者setClass(Context, Class)来指定)。通过指定具体的组件类,
通知应用启动对应的组件。
以下为直接调用 Intent,从Activity01跳转到Activity02;
Intent intent = new Intent();
intent.setClass(Activity01.this, Activity02.calss);
startActivity(intent);
间接Intent:没有指定comonent属性的Intent。这些Intent需要包含足够的信息,这样系统才能根据这些信息,在所有的可用组件中,确定满足此Intent的组件。
3、Intent的组成
Intent中一般来说最基本的应该包括:Action ,Category,与Data
若隐式调用Intent,Intent-filter 中action 是必须的,在隐式调用Intent时不指定一个确定的action,只靠其他的属性如Category,与Data是无法匹配activity的
以下Intent中可以设置的属性,在Intent-filter中是一一对应的,所以,当activity向android发送了一个,设置了一些属性Intent请求时,这个Intent会将自己的一些属性与xml中activity的Intent-filter中定义的属性去比较,若属性匹配,则可以确定要跳转的activity
Action(动作)
用来指明要实施的动作是什么,比如说ACTION_VIEW, ACTION_EDIT等。具体的可以查阅android SDK-> reference中的Android.content.intent类,里面的 constants中定义了所有的action。
Category(类别)
这个选项指定了将要执行的这个action的其他一些额外的信息,例如 LAUNCHER_CATEGORY, 表示Intent 的接受者应该在Launcher中作为顶级应用出现;而ALTERNATIVE_CATEGORY表示当前的Intent是一系列的可选动作中的一个,这些动作可以在同一块数据上执行。具体同样可以参考android SDK-> reference中的Android.content.intent类。
Data(数据)
要实施的具体的数据,一般由一个Uri变量来表示
除了Action和data这两个最基本的元素外,intent还包括一些其他的元素
Type(数据类型)
显式指定Intent的数据类型(MIME)。一般Intent的数据类型能够根据数据本身进行判定,但是通过设置这个属性,可以强制采用显式指定的类型而不再进行推导。
component(组件)
指定Intent的的目标组件的 类名称。通常 Android会根据Intent 中包含的其它属性的信息,比如action、data/type、category进行查找,最终找到一个与之匹配的目标组件。但是,如果 component这个属性有指定的话,将直接使用它指定的组件,而不再执行上述查找过程。指定了这个属性以后,Intent的其它所有属性都是可选的。
extras(附加信息)
是其它所有附加信息的集合。使用extras可以为组件提供扩展信息,比如,如果要执行“发送电子邮件”这个动作,可以将电子邮件的标题、正文等保存在extras里,传给电子邮件发送组件。
4、隐式intent的解析
在AndroidManifest.XML中会定义很多Activity,当隐式使用Intent去找到一个要跳转的目的Activity时,他如何在AndroidManifest.XML中找到这个Activity?
当隐式Intent请求到达时,他和Intent Filter进行比较匹配的三要素是Intent中的动作、数据以及类别。实际上,一个隐式Intent请求要能够传递给目标组件,必要通过这三个方面的检查。如果任何一方面不匹配,Android都不会将该隐式Intent传递给目标组件。
前面说Intent中带有一些过滤信息,当然在AndroidManifest.XML中Activity也要设置一些属性以区分彼此,例如比如用方法 setAction(),addCategory()设定了两个属性,标识自己的能力以说明,哪些过来的Intent请求是我这个Activity可以响应的,这个能力则用Intent Filter(Intent过滤器)来描述。可以声明一个甚至多个Intent Filter。每个Intent Filter描述该组件所能响应Intent请求的能力,即组件希望接收什么类型的请求行为,什么类型的请求数据。
最后,Intent-filter中定义的属性一定要全部满足Intent中设置的属性,Intent-filter中多余的属性,在匹配时忽略。属性集合的关系如下,满足这样的关系,activity才会匹配
action的匹配
一条< 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>的行为测试。
一个匹配action的小例子--一个activity中添加一个button 点击 跳转到另一个activity 并显示一个TextView
ActivityManifest.xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.testintent01"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="7"
android:targetSdkVersion="15" />
<application
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name=".TestTntent01"
android:label="@string/title_activity_test_tntent01" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".TagActivity"
android:label="@string/tagactivity_text02">
<intent-filter>
<action android:name="test.implicit.intent"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</activity>
</application>
</manifest>
TestIntent01。java
package com.android.testintent01;
import android.os.Bundle;
import android.app.Activity;
import android.content.Intent;
import android.graphics.Color;
import android.view.Menu;
import android.view.View;
import android.widget.Button;
public class TestTntent01 extends Activity
{
private Button button;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_test_tntent01);
//设置button的大小,颜色,按钮文字,透明度
button = (Button)this.findViewById(R.id.button01);
button.setText("Click to TagActivity");//--在按钮上显示文字
button.setTextSize(20);//--设置字体大小
button.setTextColor(Color.argb(100, 0, 255, 0));//--按钮文字颜色,并设置文字透明度
//Color.argb(255, 0, 255, 0)
//参数依次 透明度 blue(00 到 ff);green(00 到 ff);red(00 到 ff)。
button.setBackgroundColor(Color.GRAY);//--按钮颜色
button.getBackground().setAlpha(100);//--颜色半透明
//监听事件
button.setOnClickListener(new Button.OnClickListener()
{
public void onClick(View v)
{
Intent intent = new Intent();
intent.setAction( "test.implicit.intent");
//不加下面这行也行,因为intent的这个属性默认值即系Intent.CATEGORY_DEFAULT
intent.addCategory(Intent.CATEGORY_DEFAULT);
startActivity( intent );
}
});
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.activity_test_tntent01, menu);
return true;
}
}
个人认为这个<action android:name=“string”,是自定义,确保唯一,能匹配上就可以 把string 改成 123456 或 asdf ,只要把Intent.setAction("string");设置一样的就可以了,汉字不行。
若一个Intent请求可以在ActivityManifest.xml中有找到多个匹配action的activity怎么办?他会提示让你选择一个去执行.
Android 系统定义的常用的action 属性常量:
ACTION_MAIN:Android Application的入口,每个Android应用必须且只能包含一个此类型的Action声明。
ACTION_VIEW:系统根据不同的Data类型,通过已注册的对应Application显示数据。
ACTION_EDIT:系统根据不同的Data类型,通过已注册的对应Application编辑示数据。
ACTION_DIAL:打开系统默认的拨号程序,如果Data中设置了电话号码,则自动在拨号程序中输入此号码。
ACTION_CALL:直接呼叫Data中所带的号码。
ACTION_ANSWER:接听来电。
ACTION_SEND:由用户指定发送方式进行数据发送操作。
ACTION_SENDTO:系统根据不同的Data类型,通过已注册的对应Application进行数据发送操作。
ACTION_BOOT_COMPLETED:Android系统在启动完毕后发出带有此Action的广播(Broadcast)。
ACTION_TIME_CHANGED:Android系统的时间发生改变后发出带有此Action的广播(Broadcast)。
ACTION_PACKAGE_ADDED:Android系统安装了新的Application之后发出带有此Action的广播(Broadcast)。
ACTION_PACKAGE_CHANGED:Android系统中已存在的Application发生改变之后(如应用更新操作)发出带有此Action的广播(Broadcast)。
ACTION_PACKAGE_REMOVED:卸载了Android系统已存在的Application之后发出带有此Action的广播(Broadcast)。
如何实现点击按钮后 当前的Activity跳转到网页的浏览?这里使用到Intent的另一种带参数的构造方法
Intent(String action, Uri uri) 对于我这个初学者 我只简单的把action理解为前面系统定义的属性常量,uri是给这个action动作传进去的数据,就想我让这个Intent去访问一个网页,设置的这个action=ACTION_VIEW,这个动作就是访问浏览器,但是访问哪个网页 就需要uri去告诉这个动作action
举一个小例子 一个activity布置一个button 点击后去访问www.hao123.com
Uri uri = Uri. parse ( "http://www.hao123.com" );
Intent intent = new Intent (Intent.ACTION_VIEW , uri );
startActivity( intent );
只需要在监听事件中添加以上代码,在ActivityManifest.xml中不需要添加任何东西,点击按钮后 就直接跳转到www.hao123.com
以下是其他Action 用法 同样不需要定义新的activity 直接startActivity(Intent)
1,调web浏览器
Java代码
Uri myBlogUri = Uri.parse("http://kuikui.javaeye.com");
returnIt = new Intent(Intent.ACTION_VIEW, myBlogUri);
2,地图
Java代码
Uri mapUri = Uri.parse("geo:38.899533,-77.036476");
returnIt = new Intent(Intent.ACTION_VIEW, mapUri);
3,调拨打电话界面
Java代码
Uri telUri = Uri.parse("tel:100861");
returnIt = new Intent(Intent.ACTION_DIAL, telUri);
4,直接拨打电话
Java代码
Uri callUri = Uri.parse("tel:100861");
returnIt = new Intent(Intent.ACTION_CALL, callUri);
5,卸载
Java代码
Uri uninstallUri = Uri.fromParts("package", "xxx", null);
returnIt = new Intent(Intent.ACTION_DELETE, uninstallUri);
6,安装
Java代码
Uri installUri = Uri.fromParts("package", "xxx", null);
returnIt = new Intent(Intent.ACTION_PACKAGE_ADDED, installUri);
7,播放
Java代码
Uri playUri = Uri.parse("file:///sdcard/download/everything.mp3");
returnIt = new Intent(Intent.ACTION_VIEW, playUri);
8,掉用发邮件
Java代码
Uri emailUri = Uri.parse("mailto:shenrenkui@gmail.com");
returnIt = new Intent(Intent.ACTION_SENDTO, emailUri);
9,发邮件
Java代码
returnIt = new Intent(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, "Choose Email Client");
10,发短信
Java代码
Uri smsUri = Uri.parse("tel:100861");
returnIt = new Intent(Intent.ACTION_VIEW, smsUri);
returnIt.putExtra("sms_body", "shenrenkui");
returnIt.setType("vnd.android-dir/mms-sms");
11,直接发邮件
Java代码
Uri smsToUri = Uri.parse("smsto://100861");
returnIt = new Intent(Intent.ACTION_SENDTO, smsToUri);
returnIt.putExtra("sms_body", "shenrenkui");
12,发彩信
Java代码
Uri mmsUri = Uri.parse("content://media/external/images/media/23");
returnIt = new Intent(Intent.ACTION_SEND);
returnIt.putExtra("sms_body", "shenrenkui");
returnIt.putExtra(Intent.EXTRA_STREAM, mmsUri);
returnIt.setType("image/png");
category匹配
< intent-filter>元素可以包含< category>子元素,比如:
< intent-filter >
< category android:name=”android.Intent.Category.DEFAULT” />
< category android:name=”android.Intent.Category.BROWSABLE” />
< /intent-filter>
只有当Intent请求中所有的Category与组件中某一个IntentFilter的< category>完全匹配时,才会让该 Intent请求通过测试,IntentFilter中多余的< category>声明并不会导致匹配失败。一个没有指定任何类别测试的 IntentFilter仅仅只会匹配没有设置类别的Intent请求。
以下是category属性说明:
Category:
CATEGORY_DEFAULT:Android系统中默认的执行方式,按照普通Activity的执行方式执行。
CATEGORY_HOME:设置该组件为Home Activity。
CATEGORY_PREFERENCE:设置该组件为Preference。
CATEGORY_LAUNCHER:设置该组件为在当前应用程序启动器中优先级最高的Activity,通常为入口ACTION_MAIN配合使用。
CATEGORY_BROWSABLE:设置该组件可以使用浏览器启动。
CATEGORY_GADGET:设置该组件可以内嵌到另外的Activity中。
一般在创建Android 工程创建时 ActivityManifest.xml中Category默认为CATEGORY_LAUNCHER,即运行是加载的入口activity
date匹配
data属性是区分大小写的
Data的语法:
数据在< intent-filter>中的描述如下:
<data android:host="string"
android:mimeType="string"
android:path="string"
android:pathPattern="string"
android:pathPrefix="string"
android:port="string"
android:scheme="string" />
Data:
tel://:号码数据格式,后跟电话号码。
mailto://:邮件数据格式,后跟邮件收件人地址。
smsto://:短息数据格式,后跟短信接收号码。
content://:内容数据格式,后跟需要读取的内容。
file://:文件数据格式,后跟文件路径。
market://search?q=pname:pkgname:市场数据格式,在Google Market里搜索包名为pkgname的应用。
geo://latitude, longitude:经纬数据格式,在地图上显示经纬度所指定的位置。
Uri的格式:scheme://host:port/path or pathPrefix or pathPattern
data元素指定了希望接受的Intent请求的数据URI和数据类型,uri--通用资源标志符(Universal Resource Identifier, 简称"URI")。URI被分成三部分来进行匹配
scheme, authority/host/name, path 这些属性是可选的,但也是相互依赖的。如果没有给Intent过滤器指定scheme属性,那么所有其他的URI属性都会被忽略。如果没有给过滤器指定host属性,那么port属性和所有的路径属性都会被忽略。
scheme
是URI部分的协议例如,http:,mailto:,tel: (也可以自定义,满足唯一,但是自定义的没有什么意义)
authority/host:port/name
存放资源的主机名,是介于URI中scheme和path之间的部分(例如,www.google.com,可以加上port,www.google.com:80)匹配主机名时,Intent Filter的scheme也必须通过匹配
如果在xml中设置如下<date android:scheme="string"/>,那么在java中设置是Uri.parse("string:")或是Uri.parse("string://")格式才是正确的
path/Prefix/pathPattern
资源自身的名称,由路径表示。
Path属性指定一个完整的路径,这个路径会跟Intent对象中的路径进行匹配。PathPrefix属性只指定了部分路径,它会跟Intent对象中的路径初始部分匹配。pathPattern属性指定一个要跟Intent对象中的路径进行匹配的完整路径,但是这个路径中可以包含下列通配符:
1. 星号(*)通配符,路径中的*星号代表任意多个星号之前的那个字符,如a*,可跟a、aa、aaa、aaaa、...字符串匹配。
2. 点跟星号的组合(.*)通配符,它可以跟任意字符串进行匹配,如.*html,可以跟abchhtml、chtml、html、dssf.html、…等字符串匹配。
因为系统读取XML中的字符串时,会把’\’符号作为强制转义字符,因此就需要两次转义。例如,符号”*”要被写成”\\*”,符号’\’要被写成”\\\\”。这与Java代码中的写法基本相同。
有关这三种模式的更多信息,请看PatternMatcher类中的PATTERN_LITERAL、PATTERN_PREFIX、PATTERN_SIMPLE_GLOB的说明。
http://developer.android.com/reference/android/os/PatternMatcher.html
android:port
这个属性用于定义URI授权的端口部分。只有给过滤器指定了scheme和host属性时,这个属性才有意义
mimetype是正在匹配的数据的数据类型。当匹配数据类型时,你可以使用通配符来匹配子类型(例如,earthquakes/*)。如果Intent Filter指定一个数据类型,它必须与Intent匹配;没有指定数据的话全部匹配。
android:mimeType
也是是用来匹配 Intent 的。比如,当你使用 Intent.setType("text/plain") ,那么系统将会匹配到所有注册 android:mimeType="text/plain" 的 Activity。这里需要十分注意的是 Intent.setType(), Intent.setData,Intent.setDataAndType() 这三个方法!
- setType (mimetype)调用后设置 mimeType,然后将 data 置为 null;
- setData(date) 调用后设置 data,然后将 mimeType 置为 null;
- setDataAndType(date, mimetype) 调用后才会同时设置 data 与 mimeType。
以上这三个set的参数要与Intent-filter标签中定义的相同,才会匹配,而且区分大小写。
另外需要注意的是,如果你在 data 标签,既设置了 mimeType 又设置了 scheme 之内的,那么你的 Intent 需要同时设置匹配的 data 与 mimeType 即调用 setDataAndType ,系统才能匹配到这个 Activity(即便你 mimeType 设置为 "*/*" 也是如此)。当然,如果你没有设置 mimeType,那么调用 setData 进行匹配,如果你设置了任何的 mimeType 将不会匹配到该 Activity。
android系统中定义了多种mimeType,可以根据具体情况进行设置
以上只是简单的分析了如何通过设置Intent,去申请不同的activity,Intent中的action,date,category的具体定义了哪些被容,如何应用到实际的应用还需,具体情况,具体分析。
以上内容参考了很多其他的博客内容,具体有哪些记不住了\(^o^)/
下面有一个小例子,一个activity中定义了四个按钮,在监听事件中分别实现以下功能,通过action匹配,通过date匹配,通过mimetype匹配,通过date与mimetype匹配
layout.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" > <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:padding="@dimen/padding_medium" android:text="@string/hello_world" tools:context=".TestTntent01" /> <Button android:layout_width="fill_parent" android:layout_height="wrap_content" android:id="@+id/button01"/> <Button android:layout_width="fill_parent" android:layout_height="wrap_content" android:id="@+id/button03"/> <Button android:layout_width="fill_parent" android:layout_height="wrap_content" android:id="@+id/button04"/> <Button android:layout_width="fill_parent" android:layout_height="wrap_content" android:id="@+id/button05"/> </LinearLayout>
ActivityMainfest.xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.android.testintent01" android:versionCode="1" android:versionName="1.0" > <uses-sdk android:minSdkVersion="7" android:targetSdkVersion="15" /> <application android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme" > <activity android:name=".TestTntent01" android:label="@string/title_activity_test_intent01" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <activity android:name=".TagActivity01" android:label="@string/tagactivity_text01" > <intent-filter> <action android:name="only_action" /> <category android:name="android.intent.category.DEFAULT" /> </intent-filter> </activity> <activity android:name=".TagActivity02" android:label="@string/tagactivity_text02" > <intent-filter> <action android:name="com.android.TestIntent" /> <category android:name="android.intent.category.DEFAULT" /> </intent-filter> </activity> <activity android:name=".TagActivity03" android:label="@string/tagactivity_text03" > <intent-filter> <action android:name="com.android.TestIntent" /> <category android:name="android.intent.category.DEFAULT" /> <data android:scheme="http"/> </intent-filter> </activity> <activity android:name=".TagActivity04" android:label="@string/tagactivity_text04" > <intent-filter> <action android:name="com.android.TestIntent" /> <category android:name="android.intent.category.DEFAULT" /> <data android:mimeType="vnd.earthquake.cursor.item/*"/> </intent-filter> </activity> <activity android:name=".TagActivity05" android:label="@string/tagactivity_text05" > <intent-filter> <action android:name="com.android.TestIntent" /> <category android:name="android.intent.category.DEFAULT" /> <data android:mimeType="vnd.earthquake.cursor.item/*"/> <data android:scheme="tag05"/> </intent-filter> </activity> </application> </manifest>
TestIntent.java
package com.android.testintent01; import android.net.Uri; import android.os.Bundle; import android.app.Activity; import android.content.Intent; import android.view.View; import android.widget.Button; public class TestTntent01 extends Activity { private Button button01; private Button button03; private Button button04; private Button button05; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_test_tntent01); //设置button的大小,颜色,按钮文字,透明度 button01 = (Button)this.findViewById(R.id.button01); button01.setText("通过action匹配");//--在按钮上显示文字 // button01.setTextSize(20);//--设置字体大小 // button.setTextColor(Color.argb(100, 0, 255, 0));//--按钮文字颜色,并设置文字透明度 //Color.argb(255, 0, 255, 0) //参数依次 透明度 blue(00 到 ff);green(00 到 ff);red(00 到 ff)。 // button01.setBackgroundColor(Color.GRAY);//--按钮颜色 // button01.getBackground().setAlpha(100);//--颜色半透明 button03 = (Button)this.findViewById(R.id.button03); button04 = (Button)this.findViewById(R.id.button04); button05 = (Button)this.findViewById(R.id.button05); button03.setText("匹配action与date"); button04.setText("匹配action与mimetype"); button05.setText("匹配action与mimetype与date"); //监听事件 button01.setOnClickListener(new Button.OnClickListener() { public void onClick(View v) { Intent intent01 = new Intent(); intent01.setAction( "only_action"); startActivity( intent01 ); } }); button03.setOnClickListener(new Button.OnClickListener() { public void onClick(View v) { Intent intent03 = new Intent(); intent03.setAction( "com.android.TestIntent"); Uri uri = Uri.parse("http://");//Uri uri = Uri.parse("http:"); intent03.setData(uri); startActivity( intent03 ); } }); button04.setOnClickListener(new Button.OnClickListener() { public void onClick(View v) { Intent intent04 = new Intent(); intent04.setAction( "com.android.TestIntent"); intent04.setType("vnd.earthquake.cursor.item/*"); //intent04.setData(uri); startActivity( intent04 ); } }); button05.setOnClickListener(new Button.OnClickListener() { public void onClick(View v) { Intent intent05 = new Intent(); intent05.setAction( "com.android.TestIntent"); Uri uri = Uri.parse("tag05://"); intent05.setDataAndType(uri, "vnd.earthquake.cursor.item/*"); //intent04.setData(uri); startActivity( intent05 ); } }); } }