1.35_Intent深入解剖
----------------------------
2.Android基本的设计理念是鼓励减少组件间的耦合,因此Android提供了Intent (意图) ,Intent提供了一种通用
的消息系统,它允许在你的应用程序与其它的应用程序间传递Intent来执行动作和产生事件。使用Intent可以激活
Android应用的三个核心组件:活动、服务和广播接收器。
Intent可以划分成显式意图和隐式意图。
显式意图:调用Intent.setComponent()或Intent.setClass()方法明确指定了组件名的Intent为显式意图,显式意
图明确指定了Intent应该传递给哪个组件。
隐式意图:没有明确指定组件名的Intent为隐式意图。 Android系统会根据隐式意图中设置的动作(action)、类别
(category)、数据(URI和数据类型)找到最合适的组件来处理这个意图。
<intent-filter>
<action android:name="android.intent.action.CALL" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="tel" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.CALL" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="vnd.android.cursor.item/phone" />
</intent-filter>
------------------------------------------------------------------------------
2.对于隐式意图,Android是怎样寻找到这个最合适的组件呢?记的前面我们在定义活动时,指定了一个intent-
filter,Intent Filter(意图过滤器)其实就是用来匹配隐式Intent的,当一个意图对象被一个意图过滤器进行匹
配测试时,只有三个方面会被参考到:动作、数据(URI以及数据类型)和类别。
动作测试(Action test)
一个意图对象只能指定一个动作名称,而一个过滤器可能列举多个动作名称。如果意图对象或过滤器没有指定任
何动作,结果将如下:
• 如果过滤器没有指定任何动作,那么将阻塞所有的意图,因此所有的意图都会测试失败。没有意图能够通过这个
过滤器。
• 另一方面,只要过滤器包含至少一个动作,一个没有指定动作的意图对象自动通过这个测试
类别测试(Category test)
对于一个能够通过类别匹配测试的意图,意图对象中的类别必须匹配过滤器中的类别。这个过滤器可以列举另外的
类别,但它不能遗漏在这个意图中的任何类别。
原则上一个没有类别的意图对象应该总能够通过匹配测试,而不管过滤器里有什么。大部分情况下这个是对的。但
有一个例外,Android把所有传给startActivity()的隐式意图当作他们包含至少一个类
别:"android.intent.category.DEFAULT" (CATEGORY_DEFAULT常量)。 因此,想要接收隐式意图的活动必须在它
们的意图过滤器中包含"android.intent.category.DEFAULT"。
(带"android.intent.action.MAIN"和"android.intent.category.LAUNCHER"设置的过滤器是例外)
数据测试(Data test)
当一个意图对象中的URI被用来和一个过滤器中的URI比较时,比较的是URI的各个组成部分。例如,如果过滤器仅指
定了一个scheme,所有该scheme的URIs都能够和这个过滤器相匹配;如果过滤器指定了一个scheme、主机名但没有
路经部分,所有具有相同scheme和主机名的URIs都可以和这个过滤器相匹配,而不管它们的路经;如果过滤器指定
了一个scheme、主机名和路经,只有具有相同scheme、主机名和路经的URIs才可以和这个过滤器相匹配。当然,一
个过滤器中的路径规格可以包含通配符,这样只需要部分匹配即可。
数据测试同时比较意图对象和过滤器中指定的URI和数据类型。规则如下:
a. 一个既不包含URI也不包含数据类型的意图对象仅在过滤器也同样没有指定任何URIs和数据类型的情况下才能通
过测试。
b. 一个包含URI但没有数据类型的意图对象仅在它的URI和一个同样没有指定数据类型的过滤器里的URI匹配时才能
通过测试。这通常发生在类似于mailto:和tel:这样的URIs上:它们并不引用实际数据。
c. 一个包含数据类型但不包含URI的意图对象仅在这个过滤器列举了同样的数据类型而且也没有指定一个URI的情况
下才能通过测试。
d. 一个同时包含URI和数据类型(或者可从URI推断出数据类型)的意图对象可以通过测试,如果它的类型和过滤器
中列举的类型相匹配的话。如果它的URI和这个过滤器中的一个URI相匹配或者它有一个内容content:或者文件file:
URI而且这个过滤器没有指定一个URI,那么它也能通过测试。换句话说,一个组件被假定为支持content:和file:
数据如果它的过滤器仅列举了一个数据类型。
----------------------------------------------------------------------------------------------------
2.通过案例理解隐式意图:
匹配方式如下:
Intent intent = new Intent();//隐式意图激活Activity
intent.setAction("cn.credream.lidewei");
intent.addCategory("cn.credream.category.java");
//intent.setDataAndType(Uri.parse("itcast://www.itcast.cn/liming"), "image/jpeg");
startActivity(intent);//方法内部为Intent添加了android.intent.category.DEFAULT类别
注意:当清单文件中的action和category与代码中的匹配的时候才能隐式意图激活Activity
--------------------------------------------------------------------------------------
比如: intent.setAction("cn.credream.lidewei");
intent.addCategory("cn.credream.category.java");
<!-- 过滤参数 ,只要意图中的动作名称为这里的-->
<action android:name="cn.credream.lidewei"/>
<action android:name="cn.credream.kongbin"/>
<category android:name="cn.credream.category.java"/>
-------------------------------------------------------------
3.下面是测试的所有代码:
新建Intent项目:
/Intent/src/com/credream/intent/IntentActivity.java
package com.credream.intent;
import android.app.Activity;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.view.View;
public class IntentActivity extends Activity {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
public void openActivity(View v){
/**
* (没设数据参数的情况下)只要Intent中的Action和Category都出现在Intent-Filter中,就能
与之匹配,否则匹配失败
*/
Intent intent = new Intent();
//隐式意图激活Activity
intent.setAction("com.credream.lidewei");
intent.addCategory("com.credream.category.java");
//注意:在配置文件中
// <data android:scheme="dream" android:host="www.dream.cn" android:path="/liming"/>
//注意:这里要求了路径必须要以dream开头,主机域名必须是www.dream.cn,路径必须是/liming,这时候才
可以匹配
//以上可以不用全写,比如只写了android:scheme="dream" android:host="www.dream.cn"
//那么只要"dream://www.credream.com/lidewei"就可以匹配
//intent.setData(Uri.parse("dream://www.credream.com/lidewei"));
//这里指定匹配的内容类型:<data android:mimeType="image/*"/>
//intent.setType("image/jpeg");
//This method automatically clears any data that was previously set by setData(Uri).
//可以看到:intent.setType("image/jpeg");这段代码会清除以上的setdata的所有内容
//所以还是匹配不上,那么当把intent.setType("image/jpeg");放到intent.setData(Uri.parse
("dream://www.credream.com/lidewei"));
//也是不可以的,因为这样也会把intent.setData的数据清除.
intent.setDataAndType(Uri.parse("dream://www.credream.com/lidewei"), "image/jpeg");
startActivity(intent);
//方法内部为Intent添加了android.intent.category.DEFAULT类别
}
}
------------------------------------------------------------------------------
b./Intent/src/com/credream/intent/OtherActivity.java
package com.credream.intent;
import android.app.Activity;
import android.os.Bundle;
public class OtherActivity extends Activity
{
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.other);
}
}
----------------------------------------------------------------------
c./Intent/res/layout/main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/hello" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/button"
android:onClick="openActivity"
/>
</LinearLayout>
------------------------------------------------------
d./Intent/res/layout/other.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/content" />
</LinearLayout>
---------------------------------------------------
e./Intent/AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.credream.intent"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk android:minSdkVersion="8" />
<application
android:icon="@drawable/ic_launcher"
android:label="@string/app_name" >
<activity
android:label="@string/app_name"
android:name=".IntentActivity" >
<intent-filter >
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".OtherActivity"
android:label="@string/windowtitle" >
<!-- 意图过滤器 :-->
<intent-filter >
<!-- 过滤参数 ,只要意图中的动作名称为这里的-->
<action android:name="com.credream.lidewei"/>
<action android:name="com.credream.kongbin"/>
<category android:name="com.credream.category.java"/>
<category android:name="android.intent.category.DEFAULT"/>
<!-- 参数的类别 <category android:name="android.intent.category.DEFAULT"/>注意:
这一句一定要写在代码中用到的<category android:name="com.credream.category.java"/>
的后面,否则会抛出Activity not fond exception-->
<category android:name="cn.dream.category.php"/>
<data android:scheme="dream" android:host="www.credream.com"
android:path="/lidewei"/>
<data android:mimeType="image/*"/> -->
</intent-filter>
</activity>
</application>
</manifest>
----------------------------------------------------------------------