Intent寻找目标组件的两种方式:
· 显式Intent:通过指定Intent组件名称来实现的,它一般用在知道目标组件名称的前提下,一般是在相同的应用程序内部实现的。
· 隐式Intent:通过Intent Filter来实现的,它一般用在没有明确指出目标组件名称的前提下,一般是用于在不同应用程序之间。
一.显式Intent
一般情况下,一个Android应用程序中需要多个屏幕,即是多个Activity类,并且在这些Activity之间进行切换通过Intent机制来实现的。在同一个应用程序中切换Activity时,我们通常都知道要启动的Activity具体是哪一个,因此常用显式的Intent来实现的。
下面的例子是在同一应用程序中MainActivity启动SecondActivity,下面的代码中,主要是为“转到SecondActivity”按钮添加了OnClickListener,使得按钮被点击时执行onClick()方法,onClick()方法中则利用了Intent机制,来启动SecondActivity,关键的代码是22~25行。
main.xml
1. <?xmlversion="1.0"encoding="utf-8"?>
2. <LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"
3. android:orientation="vertical"
4. android:layout_width="fill_parent"
5. android:layout_height="fill_parent"
6. >
7. <TextView
8. android:layout_width="fill_parent"
9. android:layout_height="wrap_content"
10. android:text="@string/hello1"
11. />
12. <Button
13. android:id="@+id/btn"
14. android:layout_width="wrap_content"
15. android:layout_height="wrap_content"
16. android:text="转到SecondActivity"
17. />
18. </LinearLayout>
second.xml
1. <?xmlversion="1.0"encoding="utf-8"?>
2. <LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"
3. android:orientation="vertical"
4. android:layout_width="fill_parent"
5. android:layout_height="fill_parent"
6. >
7. <TextView
8. android:layout_width="fill_parent"
9. android:layout_height="wrap_content"
10. android:text="@string/hello2"
11. />
12. <Button
13. android:id="@+id/secondBtn"
14. android:layout_width="wrap_content"
15. android:layout_height="wrap_content"
16. android:text="返回"
17. />
18. </LinearLayout>
MainActivity.java
1. package com.android.test.activity;
2.
3. importandroid.app.Activity;
4. importandroid.content.Intent;
5. importandroid.os.Bundle;
6. importandroid.view.View;
7. importandroid.view.View.OnClickListener;
8. importandroid.widget.Button;
9.
10. publicclass MainActivity extends Activity {
11. private Button btn;
12. @Override
13. publicvoid onCreate(BundlesavedInstanceState) {
14. super.onCreate(savedInstanceState);
15. setContentView(R.layout.main);
16.
17. btn =(Button)findViewById(R.id.btn);
18. //响应按钮btn事件
19. btn.setOnClickListener(new OnClickListener() {
20. @Override
21. publicvoid onClick(View v){
22. //显示方式声明Intent,直接启动SecondActivity
23. Intent it = new Intent(MainActivity.this,SecondActivity.class);
24. //启动Activity
25. startActivity(it);
26. }
27. });
28. }
29. }
SecondActivity.java
1. packagecom.android.test.activity;
2.
3. importandroid.app.Activity;
4. import android.content.Intent;
5. importandroid.os.Bundle;
6. importandroid.view.View;
7. importandroid.view.View.OnClickListener;
8. importandroid.widget.Button;
9.
10. publicclass SecondActivity extends Activity {
11. private Button secondBtn;
12. @Override
13. protectedvoid onCreate(BundlesavedInstanceState) {
14. super.onCreate(savedInstanceState);
15. setContentView(R.layout.second);
16.
17. secondBtn=(Button)findViewById(R.id.secondBtn);
18. //响应按钮secondBtn事件
19. secondBtn.setOnClickListener(new OnClickListener() {
20. @Override
21. publicvoid onClick(View v){
22. //显示方式声明Intent,直接启动MainActivity
23. Intent intent = new Intent(SecondActivity.this,MainActivity.class);
24. //启动Activity
25. startActivity(intent);
26. }
27. });
28. }
29. }
AndroidManifest.xml清单文件,16~18行为SecondActivity在清单文件里的声明
1. <?xmlversion="1.0"encoding="utf-8"?>
2. <manifestxmlns:android="http://schemas.android.com/apk/res/android"
3. package="com.android.test.activity"
4. android:versionCode="1"
5. android:versionName="1.0">
6. <uses-sdkandroid:minSdkVersion="10"/>
7.
8. <applicationandroid:icon="@drawable/icon"android:label="@string/app_name">
9. <activityandroid:name=".MainActivity"
10. android:label="@string/app_name">
11. <intent-filter>
12. <actionandroid:name="android.intent.action.MAIN"/>
13. <categoryandroid:name="android.intent.category.LAUNCHER"/>
14. </intent-filter>
15. </activity>
16. <activityandroid:name=".SecondActivity"
17. android:label="@string/app_name">
18. </activity>
19. </application>
20. </manifest>
效果图:
二.隐式Intent
下面是同一应用程序中的Activity切换的例子,需要AndroidManifest.xml中增加Activity的声明,并设置对应的Intent Filter和Action,才能被Android的应用程序框架所匹配。
MainActivity.java
1. packagecom.android.change.activity;
2.
3. importandroid.app.Activity;
4. importandroid.content.Intent;
5. importandroid.os.Bundle;
6. importandroid.view.View;
7. importandroid.view.View.OnClickListener;
8. importandroid.widget.Button;
9.
10. publicclass MainActivity extends Activity {
11. private Button btn;
12.
13. @Override
14. publicvoid onCreate(Bundle savedInstanceState) {
15. super.onCreate(savedInstanceState);
16. setContentView(R.layout.main);
17.
18. btn = (Button)findViewById(R.id.btn);
19. // 响应按钮btn事件
20. btn.setOnClickListener(new OnClickListener() {
21. @Override
22. publicvoid onClick(View v) {
23. //实例化Intent
24. Intent it = new Intent();
25. //设置Intent的Action属性
26. it.setAction("com.android.activity.MY_ACTION");
27. // 启动Activity
28. startActivity(it);
29. }
30. });
31. }
32. }
SecondActivity.java
1. packagecom.android.change.activity;
2.
3. importandroid.app.Activity;
4. importandroid.os.Bundle;
5.
6. publicclass SecondActivity extends Activity {
7.
8. @Override
9. protectedvoid onCreate(Bundle savedInstanceState) {
10. super.onCreate(savedInstanceState);
11. setContentView(R.layout.second);
12. }
13. }
main.xml
1. <?xmlversion="1.0"encoding="utf-8"?>
2. <LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"
3. android:orientation="vertical"
4. android:layout_width="fill_parent"
5. android:layout_height="fill_parent"
6. >
7. <TextView
8. android:layout_width="fill_parent"
9. android:layout_height="wrap_content"
10. />
11. <Button
12. android:id="@+id/btn"
13. android:layout_width="wrap_content"
14. android:layout_height="wrap_content"
15. android:text="转到SecondActivity"
16. />
17. </LinearLayout>
seond.xml
1. <?xmlversion="1.0"encoding="utf-8"?>
2. <LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"
3. android:orientation="vertical"
4. android:layout_width="fill_parent"
5. android:layout_height="fill_parent"
6. >
7. <TextView
8. android:layout_width="fill_parent"
9. android:layout_height="wrap_content"
10. android:text="@string/second"
11. />
12. </LinearLayout>
AndroidManifest.xml文件的18,19行修改了Intent Filter,这样SecondActivity才能够接收到MainActivity发送的Intent。因为在MainActivity的Intent发送的动作为"com.android.activity.MY_ACTION",而在18行里,SecondActivity设置的Action也为"com.android.activity.MY_ACTION",这样就能进行匹配。
1. <?xmlversion="1.0"encoding="utf-8"?>
2. <manifestxmlns:android="http://schemas.android.com/apk/res/android"
3. package="com.android.change.activity"
4. android:versionCode="1"
5. android:versionName="1.0">
6. <uses-sdkandroid:minSdkVersion="10"/>
7.
8. <applicationandroid:icon="@drawable/icon"android:label="@string/app_name">
9. <activityandroid:name=".MainActivity"
10. android:label="@string/app_name">
11. <intent-filter>
12. <actionandroid:name="android.intent.action.MAIN"/>
13. <categoryandroid:name="android.intent.category.LAUNCHER"/>
14. </intent-filter>
15. </activity>
16. <activityandroid:name=".SecondActivity">
17. <intent-filter>
18. <action android:name = "com.android.activity.MY_ACTION" />
19. <categoryandroid:name = "android.intent.category.DEFAULT" />
20. </intent-filter>
21. </activity>
22. </application>
23. </manifest>
效果图:
对于显示Intent,Android不需要再去做解析,因为目标组件很明确。Android需要解析的是隐式Intent,通过解析,将Intent映射给可以处理该Intent的Activity,Service等。Intent的解析机制主要是通过查找已经注册在AndroidManifest.xml中的所有IntentFilter以及其中定义的Intent,最终找到匹配的Intent。
1. 显示匹配(explicit intent)
对于明确指出了目标组件名称的Intent,我们称之为“显式Intent”
1)同一个应用程序中的Activity切换
Intent i=newIntent(Test.this,TestB.class);
This.startActivity(i);
2)不同应用程序之间的Activity切换
Intent i=newIntent;
i.setClassName(“com.tope.samples.intent.simple”,”com.tope.samples.intent.simple.TestActivity”);
This.startActivity(i);
注意:对于不同应用之间的Activity的切换,这里需要在Intent Filter中设置至少一个Action,否则其他的应用将没有权限调用这个Activity。
2. 隐式匹配(implicit intent)
对于没有明确指出目标组件名称的Intent,则称之为“隐式 Intent”。 Android系统使用IntentFilter 来寻找与隐式Intent相关的对象。
显式Intent直接用组件的名称定义目标组件,这种方式很直接。但是由于开发人员往往并不清楚别的应用程序的组件名称,因此,显式Intent更 多用于在应用程序内部传递消息。比如在某应用程序内,一个Activity启动一个Service。隐式Intent恰恰相反,它不会用组件名称定义需要 激活的目标组件,它更广泛地用于在不同应用程序之间传递消息。
在显式Intent消息中,决定目标组件的唯一 要素就是组件名称,因此,如果你的Intent中已经明确定义了目标组件的名称,那么你就完全不用再定义其他Intent内容。而对于隐式Intent则 不同,由于没有明确的目标组件名称,所以必须由Android系统帮助应用程序寻找与Intent请求意图最匹配的组件。具体的选择方法 是:Android将Intent的请求内容和一个叫做IntentFilter的过滤器比较,IntentFilter中包含系统中所有可能的待选组 件。如果IntentFilter中某一组件匹配隐式Intent请求的内容,那么Android就选择该组件作为该隐式Intent的目标组件。
Android如何知道应用程序能够处理某种类型的Intent请求呢?这需要应用程序在Android-Manifest.xml中声明自己所含 组件的过滤器(即可以匹配哪些Intent请求)。一个没有声明Intent-Filter的组件只能响应指明自己名字的显式Intent请求,而无法响 应隐式Intent请求。而一个声明了IntentFilter的组件既可以响应显式Intent请求,也可以响应隐式Intent请求。在通过和 IntentFilter比较来解析隐式Intent请求时,Android将以下三个因素作为选择的参考标准。
1) Action:使用android:name特性来指定对响应的动作名。
2) Data/type:该标签允许你指定组件能作用的数据。
3) Category:使用android:category属性来指定在什么样的环境下动作才被响应。每个IntentFilter标签可以包含多个category标签。
4) Extras和flag:在解析收到Intent时是并不起作用的
举例:
1)启动android自带的打电话功能的Dialer程序。
Intent intent=new Intent(Intent.ACTION_DIAL);
startActivity(intent);
也可以为另外一个Activity加上
<action android:name="android.intent.action.DIAL" />
<category android:name="android.intent.category.DEFAULT" />
这样在匹配Action_DIAL时,会出现选择框,让用户选择是打开Dialer程序还是用户自定义的Activity。
理论上来说,如果intent不指定category,那么无论intent filter的内容是什么都应该是匹配的。但是,如果是implicitintent,android默认给加上一个CATEGORY_DEFAULT,这样的话如果intent filter中没有android.intent.category.DEFAULT这个category的话,匹配测试就会失败。所以,如果你的 activity支持接收implicit intent的话就一定要在intent filter中加入android.intent.category.DEFAULT。
例外情况是:android.intent.category.MAIN和android.intent.category.LAUNCHER的filter中没有必要加入android.intent.category.DEFAULT,当然加入也没有问题。
另外:android.intent.action.MAIN决定应用程序最先启动的Activityandroid.intent.category.LAUNCHER决定应用程序是否显示在程序列表里。