什么是Intent ?
在一个Android 应用中, Intent 是对执行某个操作的一个抽象描述, Intent 负责提供组件之间相互调用的相关信息传递,实现调用者和被调用者之间的解耦。
二、Intent 的属性:
Intent是对执行某个操作的一个抽象描述,其描述的内容包括,对执行动作 Action 的描述、对操作数据的描述、还有 4 种附加属性的描述。分别介绍如下:
Action ,对执行动作的描述,是个字符串,是对所将执行的动作的描述,在Intent 类中定义了一些字符串常量作为标准动作,譬如:
public static final String ACTION_DIAL = "android.intent.action.DIAL" ;
public static final String ACTION_SENDTO = "android.intent.action.SENDTO" ;
还可以自定义Action ,并定义相应的 Activity 来处理我们自定义的行为。
data ,是对执行动作所要操作的数据的描述,Android 中采用 URI 来表示数据,譬如在联系人应用中, 指向联系人 1 的 URI 可能为: content://contacts/1 ( 由 content provider 提供的数据类型是 content) 。 结合 Action 和 data 可以基本表达出意图 ,
· VIEW_ACTION content://contacts/1 — 显示标识符为 ”1″ 的联系人的详细信息
· EDIT_ACTION content://contacts/1 — 编辑标识符为 ”1″ 的联系人的详细信息
· VIEW_ACTION content://contacts/ — 显示所有联系人的列表
· PICK_ACTION content://contacts/ — 显示所有联系人的列表,并且允许用户在列表中选择一个联系人,然后把这个联系人返回给父 activity 。例如:电子邮件客户端可以使用这个 Intent ,要求用户在联系人列表中选择一个联系人。
除了Action 和 data 之外,还有 4 个属性。
catagory 类别 ,是被请求组件的额外描述信息,Intent 类中也定义了一组字符串常量表示 Intent 不同的类别。完整的列表可以看 API 文档中 Intent 类的相应部分。
public static final String CATEGORY_LAUNCHER = "android.intent.category.LAUNCHER" ; Public static final String CATEGORY_PREFERENCE = "android.intent.category.PREFERENCE" ; |
extra 附加信息, 除了data 之外,还可以通过 extra 附加信息, extra 属性使用 Bundle 类型 进行数据传递,我们可以把 Bundle 当做 HashMap 来理解,附加数据可以通过 intent.putExtras() 和 intent.getExtras() 进行传入和读取。 就像这样,获取附加信息: Bundle bundle = intent.getExtras();
添加附加信息: Bundle bundle = new Bundle(); intent.putExtras(bundle);
component 组件 ,显式指定Intent 的目标组件的名称。如果指定了 component 属性,系统会直接使用它指定的组件,而非匹配查找。
type 数据类型, 显式指定Intent 的数据类型,一般 Intent 的数据类型都能够根据数据本身进行判定,但是通过设置这个属性,可以强制采用显式指定的类型和不再进行推导。 、
解析Intent
Intent是一种在不同组件之间传递的请求信息,是应用程序发出的请求和意图,作为一个完整的消息传递机制, Intent 不仅需要发送端,还需要接收端。
当指定了component 属性后,就是显式的指定了目标组件,也就是接收端。如果没有明确指定目标组件,那么 Android 系统会使用 Intent 里的( action , data , category )三个属性来寻找和匹配接收端。
IntentFilter
应用程序组件可以使用IntentFilter 来向系统说明自己可以响应和处理那些 Intent 请求。组件一般通过 AndroidManifest.xml 文件的 <Intent-Filter> 描述。
< activity android:name = ".ButtonDemo" android:label = "@string/app_name" > < intent-filter > < action android:name = "android.intent.action.MAIN" /> < category android:name = "android.intent.category.LAUNCHER" /> </ intent-filter > </ activity > |
Intent的用法
一、 显式的 Intent(Explicit Intent)
² 同一个应用程序中的Activity切换
通常一个应用程序中需要多个 UI 屏幕,也就需要多个 Activity 类,并且在这些 Activity 之间进行切换,这种切换就是通过 Intent 机制来实现的。
在同一个应用程序中切换 Activity 时,我们通常都知道要启动的 Activity 具体是哪一个,因此常用显式的 Intent 来实现。下面的例子用来实现一个非常简单的应用程序 IntentDemo ,它包括两个 UI 屏幕也就是两个 Activity—— IntentDemo 类和 TestView 类, IntentDemo 类有一个 按钮用来启动 Test View ,
程序的代码非常简单, IntentDemo类源代码
package com.wang.android.demo.intent; import android.app.Activity; import android.content.Intent; import android.os.Bundle; import android.view.View; import android.widget.Button; public class IntentDemo extends Activity { public void onCreate(Bundle savedInstanceState) { super .onCreate(savedInstanceState); setContentView(R.layout. main ); Button start_button=(Button)findViewById(R.id. Start ); start_button.setOnClickListener( new Button.OnClickListener(){ public void onClick(View v) { Intent intent = new Intent(); intent.setClass(IntentDemo. this , TestView. class ); startActivity(intent); }}); } } |
上面的代码中,主要是为“ Start _ activity ”按钮添加了 OnClickListener , 使得按钮被点击时执行 onClick() 方法, onClick() 方法中则利用了 Intent 机制,来启动 Test View ,关键的代码是下面这 几 行:
Intent intent = new Intent(); intent.setClass(IntentDemo. this , TestView. class ); startActivity(intent); |
这里定义 Intent 对象时所用到的是 Intent 的构造函数之一:
Intent ( Context packageContext, Class <?> cls)
两个参数分别指定 Context 和 Class ,由于将 Class 设置为 TestActivity.class ,这样便显式的指定了 Test View 类作为该 Intent 的 接收者,通过后面的startActivity() 方法便可启动 Test View 。
TestView.java类的源代码:
package com.wang.android.demo.intent;
import android.app.Activity; import android.os.Bundle;
public class TestView extends Activity{ protected void onCreate(Bundle savedInstanceState) { // TODO Auto-generated method stub super .onCreate(savedInstanceState); setContentView(R.layout. test_activity ); } } |
Test View 仅仅是调用 setContentView 来显示 test_ View .xml 中的内容而已。
下一步在 AndroidManifest.xml 文件中注册 Activity。 AndroidManifest.xml 源代码如下:
<? xml version = "1.0" encoding = "utf-8" ?> < manifest xmlns:android = "http://schemas.android.com/apk/res/android" package = "com.wang.android.demo.intent" android:versionCode = "1" android:versionName = "1.0" > < application android:icon = "@drawable/icon" android:label = "@string/app_name" > < activity android:name = ".IntentDemo" android:label = "@string/app_name" > < intent-filter > < action android:name = "android.intent.action.MAIN" /> < category android:name = "android.intent.category.LAUNCHER" /> </ intent-filter > </ activity > < activity android:name = ".TestView" ></ activity > </ application > < uses-sdk android:minSdkVersion = "8" /> </ manifest > |
I ntent 机制即使在 程序内部 且 显式指定 接收者,也还是需要在 AndroidManifest.xml 中声明。这个过程并不像一个简单的函数调用,显式的 Intent 也同样 经过了Android 应用程序框架所提供的支持,从满足条件的 Activity 中进行选择,如果不在 AndroidManifest.xml 中进行声明,则 Android 应用程序框架找不到所需要的 Activity 。
² 不同应用程序之间的Activity切换
上面的例子我们所做的是在同一应用程序中进行 Activity 的切换,那么在不同的应用程序中,是否也能这么做呢,答案是肯定的,不过对应的代码要稍作修改。本例中我们需要两个应用程序,可利用上例中的 IntentDemo , 新建一个 IntentTest 应用程序。
IntentTest 源代码:
package com.android.demo.intent;
import android.app.Activity; import android.content.Intent; import android.os.Bundle; import android.view.View; import android.widget.Button;
public class IntentTest extends Activity { /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super .onCreate(savedInstanceState); // 按照main.xml來渲染用戶界面 setContentView(R.layout. main ); Button start_button = (Button) findViewById(R.id. StartButton ); // 为拨号按钮设置一个点击事件观察者 start_button.setOnClickListener( new Button.OnClickListener() { // 实现监听器接口的匿名内部类,其中监听器本身是View类的内部接口 // 实现接口必须实现的onClick方法 @Override public void onClick(View v) { Intent intent = new Intent(); intent.setClassName( "com.wang.android.demo.intent" , "com.wang.android.demo.intent.TestView" ); // 去调用那些可以处理拨号行为的Activity startActivity(intent); } }); } } |
注意比较它与 IntentDemo t 的不同之处主要在于初始化 Intent 对象的过程:
Intent intent = new Intent(); intent.setClassName( "com.wang.android.demo.intent" , "com.wang.android.demo.intent.TestView" );
|
这里采用了 Intent 最简单的不带参数的构造函数,然后通过 setClassName() 函数来指定要启动哪个包中的哪个 Activity , 而不是像上例中的通过 Intent ( Context packageContext, Class <?> cls) 这个构造函数来初始化Intent 对象,这是因为,要启动的 TestActivity与 CrossIntentTest 不在同一个包中,要指定 Class 参数比较麻烦,所以通常启动不同程序的 Activity 时便采用上面的 setClassName() 的方式
另外我们还需要修改SimpleIntentTest 程序中的 AndroidManifest.xml 文件,为 TestActivity 的声明添加 Intent Filter ,
< activity android:name = ".TestView" > < intent-filter > < action android:name = "android.intent.action.DEFAULT" /> </ intent-filter > </ activity > |
对于不同应用之间的 Activity 的切换,这里需要在 Intent Filter 中设置至少一个 Action ,否则其他的应用将没有权限调用这个 Activity 。 设置Intent Filter 和 Action 主要的目的,是为了让其他需要调用这个 Activity 的程序能够顺利的调用它。除了 Action 之外, Intent Filter 还可以设置 Category 、 Data 等,用来更加精确的匹配 Intent 与 Activity 。
隐式 Intent(Implicit Intent)
如果 Intent 机制仅仅提供上面的显式 Intent 用法的话,这种相对复杂的机制似乎意义并不是很大。确实, Intent 机制更重要的作用在于下面这种隐式的 Intent ,即 Intent 的发送者不指定接收者,很可能不知道也不关心接收者是谁,而由 Android 框架去寻找最匹配的接收者。
² 最简单的隐式Intent
将IntentDemo 稍做修改,做一个简单的拨打电话的 demo 。源代码如下:
package com.wang.android.demo.intent;
import android.app.Activity; import android.content.Intent; import android.net.Uri; import android.os.Bundle; import android.view.View; import android.widget.Button; import android.widget.EditText;
public class IntentDemo extends Activity { /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super .onCreate(savedInstanceState); // 按照main.xml來渲染用戶界面 setContentView(R.layout. main ); // 获取可编辑的电话号码框和拨号按钮 final EditText phoneNumberEditText = (EditText) findViewById(R.id. PhoneNumberEditText ); Button dialing = (Button) findViewById(R.id. dialing ); // 为拨号按钮设置一个点击事件观察者 dialing.setOnClickListener( new Button.OnClickListener() { // 实现监听器接口的匿名内部类,其中监听器本身是View类的内部接口 // 实现接口必须实现的onClick方法 @Override public void onClick(View v) { // 获得可编辑文本框中的值,也就是电话号码 String phoneNumber = phoneNumberEditText.getText().toString(); // new Intent(行为,数据),其中action_dial是拨号行为,数据是电话号码 Intent intent = new Intent(Intent. ACTION_DIAL , Uri . parse ( "tel://" + phoneNumber)); // 去调用那些可以处理拨号行为的Activity startActivity(intent); } }); } } |
Main.xml 源代码:
<? xml version = "1.0" encoding = "utf-8" ?> < LinearLayout xmlns:android = "http://schemas.android.com/apk/res/android" android:orientation = "vertical" android:layout_width = "fill_parent" android:layout_height = "fill_parent" > < EditText android:id = "@+id/PhoneNumberEditText" android:text = "请输入电话号码" android:textSize = "15sp" android:layout_width = "fill_parent" android:layout_height = "wrap_content" ></ EditText > < Button android:id = "@+id/dialing" android:text = "@string/dialing" android:layout_width = "wrap_content" android:layout_height = "wrap_content" ></ Button > </ LinearLayout >
|
AndroidManifest.xml 源代码:
<? xml version = "1.0" encoding = "utf-8" ?> < manifest xmlns:android = "http://schemas.android.com/apk/res/android" package = "com.wang.android.demo.intent" android:versionCode = "1" android:versionName = "1.0" > < application android:icon = "@drawable/icon" android:label = "@string/app_name" > < activity android:name = ".IntentDemo" android:label = "@string/app_name" > < intent-filter > < action android:name = "android.intent.action.MAIN" /> < category android:name = "android.intent.category.LAUNCHER" /> < intent-filter > < action android:name = "android.intent.action.CALL_BUTTON" ></ action > < category android:name = "android.intent.category.DEFAULT" > </ category > </ intent-filter > </ intent-filter > </ activity > </ application > < uses-sdk android:minSdkVersion = "8" />
</ manifest > |
² 增加一个接收者
事实上接收者如果希望能够接收某些 Intent ,通过在 AndroidManifest.xml 中增加 Activity 的声明,并设置对应的 Intent Filter 和 Action ,才能被 Android 的应用程序框架所匹配。
AndroidManifest.xml 文件,将 IntentDemo 的声明部分改为:
< activity android:name = ".IntentDemo" android:label = "@string/app_name" > < intent-filter > < action android:name = "android.intent.action.MAIN" /> < category android:name = "android.intent.category.LAUNCHER" /> < intent-filter > < action android:name = "android.intent.action.CALL_BUTTON" ></ action > < category android:name = "android.intent.category.DEFAULT" ></ category > </ intent-filter > </ intent-filter > </ activity > |