`
1874
  • 浏览: 9604 次
社区版块
存档分类
最新评论

Android Intent机制实例详解(Activity篇)转

阅读更多

Android Intent机制实例详解(Activity篇) http://www.uml.org.cn/mobiledev/201208211.asp

 

Android 中提供了 Intent 机制来协助应用间的交互与通讯,或者采用更准确的说法 是, Intent 不仅可用于应用程序之间,也可用于应用程序内部的 Activity/Service 之间的交互。 Intent 这个英语单词的本意是“目的、意向”等,对于较少从事 于大型平台开发工作的程序员来说, 这可能 是一个不太容易理解的抽象概念,因为它与我们平常使用的简单函数/ 方法调用,或者上节中提到的通过库调用接口的方式不太一样。在 Intent 的使用中你看不到直接的函数调用,相对函数调用来说, Intent 是更为抽象的概念,利用 Intent 所实现的软件复用的粒度是Activity/Service ,比函数复用更高一些,另外耦合也更为松散。

Android 中与Intent 相关的还有 Action/Category 及 Intent Filter 等,另外还有用于广播的 Intent ,这些元素掺杂在一起,导致初学者不太容易迅速掌握 Intent 的用法。在讲解这些名词之前,我们先来从下面的例子中 感受一下 Intent 的一些基本用法,看看它能做些什么,之后再来思考这种机制背后的意义。

理解 Intent 的关键之一是理解清楚Intent 的两种基本用法:一种是显式的 Intent ,即在构造 Intent 对象时就指定接收者,这种方式与普通的函数调用类似, 只是复用的粒度有所差别;另一种是隐式的 Intent ,即Intent 的发送者在构造 Intent 对象时,并不知道也不关心接收者是谁,这种方式与函数调用差别比较大,有利于降低发送者和接收 者之间的耦合。另外 Intent 除了发送外,还可用于广播,这些都将在后文进行详细讲述。

下面的一小节我们来看看显式 Intent 的用法。

显式的 Intent(Explicit Intent)

同一个应用程序中的Activity切换

我们在前面的章节已经讨论过 Activity 的概念,通常一个应用程序中需要多个UI 屏幕,也就需要多个Activity 类,并且在这些 Activity 之间进行切换,这种切换就是通过 Intent 机制来实现的。

在同一个应用程序中切换 Activity时,我们通常都知道要启动的 Activity 具体是哪一个,因此常用显式的 Intent 来实现。下面的例子用来实现一个非常简单的应用程序 SimpleIntentTest ,它包括两个UI 屏幕也就是两个 Activity——SimpleIntentTest类和 TestActivity 类, SimpleIntentTest类有一个按钮用来启动 TestActivity。

程序的代码非常简单, SimpleIntentTest类的源代码如下:

package  com.tope.samples.intent.simple;

import  android.app.Activity;
import  android.content.Intent;
import  android.os.Bundle;
import  android.view.View;
import  android.widget.Button;

public   class  SimpleIntentTest  extends  Activity  implements  View.OnClickListener{
     /**   Called   when   the   activity   is   first   created.   */
     @Override
     public   void  onCreate(Bundle savedInstanceState) {
         super .onCreate(savedInstanceState);
        setContentView(R.layout. main );
        Button startBtn = (Button)findViewById(R.id. start_activity );
        startBtn.setOnClickListener( this );
    }
 
     public   void  onClick(View v) {
         switch  (v.getId()) {
         case  R.id. start_activity :
            Intent intent =  new  Intent( this , TestActivity. class );
            startActivity(intent);
             break ;
         default :
             break ;
         }
    }   
}

 

上面的代码中,主要是为“ Start activity ” 按钮添加了 OnClickListener, 使得按钮被点击时执行 onClick() 方法, onClick() 方法中则利用了 Intent 机制,来启动 TestActivity,关键的代码是下面这两行:

Intent intent = new Intent( this , TestActivity. class );

startActivity(intent);

这里定义 Intent 对象时所用到的是 Intent 的构造函数之一:

Intent ( Context packageContext, Class <?> cls)

两个参数分别指定 Context 和 Class ,由于将Class 设置为 TestActivity.class,这样便显式的指定了TestActivity 类作为 该Intent 的 接收者,通过后面的startActivity() 方法便可启动 TestActivity 。

TestActivity 的代码更为简单(定义 TestActivity类需要新建 TestActivity.java 文件,如果你是一个初学者,你需要学会如何在 Eclipse 或其他开发环境下添加一个新的类,本书不作详述,请参 考其他文档),如下所示:

package  com.tope.samples.intent.simple;

import  android.app.Activity;
import  android.os.Bundle;

public   class  TestActivity  extends  Activity {
     /**   Called   when   the   activity   is   first   created.   */
     @Override
     public   void  onCreate(Bundle savedInstanceState) {
         super .onCreate(savedInstanceState);
        setContentView(R.layout. test_activity );
    }
} 

 

可见 TestActivity仅仅是调用 setContentView 来显示 test_activity.xml 中的内容而已。对于 test_activity.xml及 本例中所用到其他 xml 文件这里不作多余说明,读者练习时可自行参考本书所附光盘中的源代码。

如果我们仅仅是做上面的一些 工作,还不能达到利用 SimpleIntentTest 启动 TestActivity的目的。事实上,这样做 会出现下面的 Exception ,导致程序退出。以下是利用 logcat 工具记录的log 信息(省略了后半部分):

I/ActivityManager(  569): Displayed activity com.tope.samples/.SimpleIntentTest: 3018 ms
I/ActivityManager(  569): Starting activity: Intent { comp={com.tope.samples/com.tope.samples.TestActivity} }
D/AndroidRuntime(  932): Shutting down VM
W/dalvikvm(  932): threadid=3: thread exiting with uncaught exception (group=0x4000fe70)
E/AndroidRuntime(  932): Uncaught handler: thread main exiting due to uncaught exception
E/AndroidRuntime(  932):  android.content.ActivityNotFoundException: Unable to find explicit activity class
 {com.tope.samples/com.tope.samples.TestActivity}; have you declared this activity in your AndroidManifest.xml?
E/AndroidRuntime(  932):     at android.app.Instrumentation.checkStartActivityResult(Instrumentation.java:1480)
E/AndroidRuntime(  932):     at android.app.Instrumentation.execStartActivity(Instrumentation.java:1454)
E/AndroidRuntime(  932):     at android.app.Activity.startActivityForResult(Activity.java:2656)
E/AndroidRuntime(  932):     at android.app.Activity.startActivity(Activity.java:2700)
E/AndroidRuntime(  932):     at com.tope.samples.SimpleIntentTest.onClick(SimpleIntentTest.java:24)
…  

 

从这些log 中我们可以看到点击按钮后 startActivity 的调用过程,主要的原因是:“android.content.ActivityNotFoundException: Unable to find explicit activity class {com.tope.samples/com.tope.samples.TestActivity}; have you declared this activity in your AndroidManifest.xml?”

从这些log 我们可以看到原因是找不到 TestActivity这个 Activity ,并且 log 中还给出了提示:你是否在AndroidManifest.xml 中声明了这个 Activity?解决问题的方法也就是按照提示在 AndroidManifest.xml 中增加TestActivity 的声明,如下所示,注意粗体字部分:

<? xml   version = "1.0"   encoding = "utf-8" ?>
< manifest   xmlns:android = "http://schemas.android.com/apk/res/android"
       package = "com.tope.samples"
       android:versionCode = "1"
       android:versionName = "1.0" >
     < application   android:icon = "@drawable/icon"   android:label ="@string/app_name" >
         < activity   android:name = ".SimpleIntentTest"
                   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 = ".TestActivity" />
     </ application >
     < uses-sdk   android:minSdkVersion = "3"   />
</ manifest >  

 

完成这个修改后再重新运行该 程序,就一切都正常了。

从 AndroidManifest.xml修改的过程我们可以体会到, Intent 机制即使在 程序内部 且 显式指定 接收者,也还是需要在 AndroidManifest.xml 中声明 TestActivity。这个过程并不像一个简单的函数调用,显式的 Intent 也同样 经过了Android 应用程序框架所提供的支持,从满足条件的 Activity 中进行选择,如果不在 AndroidManifest.xml中进行声明,则 Android 应用程序框架找不到所需要的 Activity。

请读者通过我们的示例来逐步 理解 AndroidManifest.xml在这个过程中所扮演的角色,这样有利于理解 Intent的作用 ,及后面的 Intent Filter。当然,这个例子仅仅是开始,且看下文分解 。

不同应用程序之间的Activity切换

上面的例子我们所做的是在同 一应用程序中进行 Activity 的切换,那么在不同的应用程序中,是否也能这么做呢,答案是肯定的,不过对应的代码要稍作修改。本例中我们需要两个应用程序,可利用上例中 的SimpleIntentTest作为其中之一,另外还需要写一个新的程序,来调用 SimpleIntentTest 应用程序中的 TestActivity。

我们新建程序 CrossIntentTest(注意不是新建一个类,如果是 Eclipse 环境,选择 File->New->Project新建工程),其中只有一个 Activity ,其源代码与 SimpleIntentTest.java 类似 :

	
package  com.tope.samples.intent.cross;

import  android.app.Activity;
import  android.content.Intent;
import  android.os.Bundle;
import  android.view.View;
import  android.widget.Button;

public   class  CrossIntentTest  extends  Activity 
     implements  View.OnClickListener{
     /**   Called   when   the   activity   is   first   created.   */
     @Override
     public   void  onCreate(Bundle savedInstanceState) {
         super .onCreate(savedInstanceState);
        setContentView(R.layout. main );
        Button startBtn = (Button)findViewById(R.id. start_activity );
        startBtn.setOnClickListener( this );
    }
 
     public   void  onClick(View v) {
         switch  (v.getId()) {
         case  R.id. start_activity :
            Intent intent =  new  Intent();
            intent.setClassName( "com.tope.samples.intent.simple" , 
                     "com.tope.samples.intent.simple.TestActivity" );
            startActivity(intent);
             break ;
         default :
             break ;
        }
    }   
}

 

注意比较它与 SimpleIntentTest的不同之处主要在于初始化 Intent 对象的过程:

	
Intent intent =  new  Intent();
intent.setClassName( "com.tope.samples.intent.simple" , 
                     "com.tope.samples.intent.simple.TestActivity" );
startActivity(intent);

 

这里采用了 Intent 最简单的不带参数的构造函数 , 然后通过 setClassName() 函数来指定要启动哪个包中的哪个 Activity, 而不是像上例中的通过 Intent ( Context packageContext, Class <?> cls) 这个构造函数来初始化Intent 对象 , 这是因为 , 要启动的 TestActivity 与 CrossIntentTest 不在同一个包中 , 要指定 Class 参数比较麻烦 , 所以通常启动不同程序的 Activity 时便采用上面的 setClassName() 的方式。除此之外,你也可以利用Android 提供的类似的 setComponent() 方法,具体使用方法请参考 Android SDK的文档。

另 外我们还需要修改SimpleIntentTest 程序中的 AndroidManifest.xml 文件,为 TestActivity 的声明添加Intent Filter ,即将原来的

	
< activity android:name = ".TestActivity" />

 修改为:

< activity   android:name = ".TestActivity" >
             < intent-filter >
                 < action   android:name = "android.intent.action.DEFAULT"  />
             </ intent-filter >
</ activity > 

 

对于不同应用之间的 Activity 的切换,这里需要在 Intent Filter中 设置至少一个 Action,否则其他的应用将没有 权限调用这个 Activity 。这里我们开始接触 Intent Filter和 Action 这 些 概念了,读者应该可以感觉到,设置Intent Filter 和 Action 主要的目的,是为了让其他需要调用这个 Activity 的程序能够顺利的调用它。除了Action之外, Intent Filter 还可以设置 Category 、 Data等,用来更加精确的匹配 Intent 与 Activity,这在后文将有详细介绍 。

程序运行的截图与上例类似,这里就不再重复了。

隐式 Intent(Implicit Intent)

如果 Intent 机制仅仅提供上面的显式 Intent 用法的话,这种相对复杂的机制似乎意义并不是很大。确 实,Intent 机制更重要的作用在于下面这种隐式的 Intent ,即 Intent 的发送者不指定接收者,很可能不知道也不关心接收者是谁,而由 Android 框架去寻找最匹配的接收者。

最简单的隐式 Intent

我们先从最简单的例子开始。 下面的 ImplicitIntentTest 程序用来启动 Android 自带的打电话功能的 Dialer 程序。

ImplicitIntentTest 程序只包含一个java 源文件 ImplicitIntentTest.java,代码如下所示:

 

package  com.tope.samples.intent.implicit;

import  android.app.Activity;
import  android.content.Intent;
import  android.os.Bundle;
import  android.view.View;
import  android.widget.Button;

public   class  ImplicitIntentTest  extends  Activity     
     implements  View.OnClickListener{
     /**   Called   when   the   activity   is   first   created.   */
     @Override
     public   void  onCreate(Bundle savedInstanceState) {
         super .onCreate(savedInstanceState);
        setContentView(R.layout. main );
        Button startBtn = (Button)findViewById(R.id. dial );
        startBtn.setOnClickListener( this );
    }
 
     public   void  onClick(View v) {
         switch  (v.getId()) {
         case  R.id. dial :
            Intent intent =  new  Intent(Intent. ACTION_DIAL );
            startActivity(intent);
             break ;
         default :
             break ;
        }
    }   
} 

 

该 程序在Intent 的使用上,与上节中的使用方式有很大的不同,即根本不指 定接收者,初始化 Intent 对象时,只是传入参数,设定 Action为 Intent.ACTION_DIAL :

Intent intent = new Intent(Intent. ACTION_DIAL );

startActivity(intent);

这里使用的构造函数的原型如 下:

Intent ( String action);

有关 Action 的作用后文将有详细说明,这里读者可暂时将它理解为描 述这个 Intent 的一种方式,这种使用方式看上去比较奇怪, Intent 的发送者只是指定了 Action为 Intent.ACTION_DIAL ,那么怎么找到 接收者呢?来看下面的例子。

增加一个接收者

事实上接收者如果希望能够接 收某些 Intent ,需要像上节例子中一样,通过在 AndroidManifest.xml中增加Activity 的声明,并设置对应的 Intent Filter 和 Action ,才能被 Android 的应用程序框架所匹配。为了证明这一点,我们修改上一 节 SimpleIntentTest 程序中的 AndroidManifest.xml 文件,将 TestActivity 的声明部分改为:

 <activity   android:name = ".TestActivity" >
         <intent-filter >
             <action   android:name = "android.intent.action.DEFAULT"   />
             <action   android:name = "android.intent.action.DIAL"   />
             <category   android:name = "android.intent.category.DEFAULT"  />
         </intent-filter >
  </activity > 

 

修改完之后注意要重新安装 SimpleIntentTest 程序的apk 包,然后再尝试运行 ImplicitIntentTest 程序(不是SimpleIntentTest 程序)

这个截图中的第二幅表示可以 选择 Dialer 或者 SimpleIntentTest 程序来完成 Intent.ACTION_DIAL ,也就是说,针对 Intent.ACTION_DIAL, Android 框架找到了两个符合条件的 Activity,因此它将这两个 Activity 分别列出,供用户选择。

回过头来看我们是怎么做到这 一点的。我们仅仅在 SimpleIntentTest 程序的 AndroidManifest.xml 文件中增加了下面的两行:

	
< action android:name = "android.intent.action.DIAL" />
< category android:name = "android.intent.category.DEFAULT" />

 这两行修改了原来的 Intent Filter,这样这个 Activity 才能够接收到我们发送的 Intent 。我们通过这个改动及其作用,可以进一步理解隐式 Intent, Intent Filter 及 Action, Category 等概念—— Intent 发送者设定 Action 来说明将要进行的动作,而 Intent 的接收者在 AndroidManifest.xml 文件中通过设定 Intent Filter来声明自己能接收哪些Intent 。

分享到:
评论

相关推荐

    AndroidIntent机制实例详解(Activity篇)

    Android中提供了Intent机制来协助应用间的交互与通讯,或者采用更准确的说法 是,Intent不仅可用于应用程序之间,也可用于应用程序内部的Activity/Service之间的交互。 Intent这个英语单词的本意是“目的、意向”等...

    Android Intent封装的实例详解

    Android Intent封装的实例详解 什么是Intent: Intent是协调应用间、组件之间的通讯和交互。通过Intent你可以启动Activity、Service、Broadcasts。更可以跨程序调用第三方组件。例如:启动拨打电话界面、音乐播放等...

    Android核心技术与实例详解

    Android核心技术与实例详解是一本pdf电子书。全书结合真实的案例,向读者介绍了Android的基本组件的使用及应用程序开发的整个流程。此书适合Android初学者,也适合具备一定Android开发经验但需要开发实例的高级读者...

    Android核心技术与实例详解 PDF扫描版

    Android核心技术与实例详解 图书简介: 本书以Android应用程序的开发为主题 并结合真实的案例向读者详细介绍了Android的基本组件的使用及应用程序开发的整个流程 全书分为三篇共18章 第一篇以简单易懂的实例为依托 ...

    Android 两种启动模式的实例详解

    Android 两种启动模式的实例详解 Intent的FLAG_ACTIVITY_CLEAR_TOP和FLAG_ACTIVITY_REORDER_TO_FRONT Activity的两种启动模式:FLAG_ACTIVITY_CLEAR_TOP和FLAG_ACTIVITY_REORDER_TO_FRONT 1. 如果已经启动了四个...

    Android startActivityForResult实例详解

    Android startActivityForResult实例详解 startActivityForResult用于两个activity之间的数据传递,Activity1传值给Activity2,Activity2再返回值给Activity1。 第一步:Activity1中:startActivityForResult(Intent...

    Android中Intent传递对象的3种方式详解

    相信Intent的用法大家已经比较熟悉了,Intent可以用来启动Activity,Service等等,同时我们也可以通过Intent来进行传递数据,当我们使用Intent在Activity 间传递信息时发现putExtra() 方法并不支持自定义对象的传输...

    Android开发应用实战详解源代码

    1.1 初识android 1.1.1 历史背景 1.1.2 android特性 1.1.3 android组件结构 1.1.4 android应用程序框架 1.1.5 android的竞争优势 1.1.6 android模拟器 1.2 搭建android开发环境 1.2.1 准备工作 1.2.2 windows系统下...

    Android入门到精通源代码.

    11.4 应用实例详解:确定当前 位置的GPS程序 11.4.1 实例分析 11.4.2 实例实现 11.5 基于Google Map的应用 11.5.1 使用MapView显示地图 11.5.2 使用MapController控制地图缩放 11.6 应用实例详解:普通地图和 卫星...

    Android Activity切换动画详解及实例

    Android Activity切换动画 Android Activity切换动画是指从Activity A 跳转至Activity B的时候,Activity A 有退出动画,Activity B 有进入动画。这个动画的实现很简单,在startActivity(intent)之后调...

    Android开发中使用Intent打开第三方应用及验证可用性的方法详解

    本文实例讲述了Android开发中使用Intent打开第三方应用及验证可用性的方法。分享给大家供大家参考,具体如下: Android中提供了Intent机制来协助应用间的交互与通讯。可作为不同组件之间通讯的媒介完成应用之间的...

    Android activity堆栈及管理实例详解

    本示例演示如何通过设置Intent对象的标记,来改变当前任务堆栈中既存的Activity的顺序。 1. Intent对象的Activity启动标记说明: FLAG_ACTIVITY_BROUGHT_TO_FRONT 应用程序代码中通常不设置这个标记,而是由系统给...

    Android Activity启动模式之singleTop实例详解

    在前面文章《Android Activity启动模式之standard实例详解》中,我们介绍了活动的默认启动模式standard,本文继续介绍Activity的singleTop模式。 singleTop模式:当Activity的活动模式设置为singleTop时,在启动活动...

    Android应用开发详解pdf版

    对Acitivit之间的Intent意图驱动机制也讲解得很详细。 要强调一点的是:第三章Android中的资源访问,这章节非常不错,将android工程的目录结构、工程内每个文件之间的组合,联系,访问都讲解得非常不错,我觉得掌握...

    Android 中 ActivityLifecycleCallbacks的实例详解

    Android 中 ActivityLifecycleCallbacks的实例详解  以上就是使用ActivityLifecycleCallbacks的实例,代码注释写的很清楚大家可以参考下, MyApplication如下: package com.cc; import java.util.LinkedList; ...

    Android编程实现全局获取Context及使用Intent传递对象的方法详解

    本文实例讲述了Android编程实现全局获取Context及使用Intent传递对象的方法。分享给大家供大家参考,具体如下: 一、全局获取 Context Android 开发中很多地方需要用到 Context,比如弹出 Toast、启动活动、发送广播...

    Android实例代码

    5.1、Intent对象详解: 5.2、Intent的属性及intent-filter配置:Component属性; Action、Category属性与intent-filter配置; Data、Type属性与intent-filter配置; Extra属性; 5.3、使用Intent创建Tab页面: 第6章...

    Android编程中Intent实现页面跳转功能详解

    本文实例讲述了Android编程中Intent实现页面跳转功能。分享给大家供大家参考,具体如下: 安卓四大组件:Activity、Service、Broadcast Receiver、Content Provider Intent实现页面之间跳转 1、无返回值 start...

    Android拨打电话功能实例详解

    本文实例分析了Android拨打电话功能。分享给大家供大家参考,具体如下: 打电话是手机的一个最基本的功能,现在android智能手机非常流行,里面有多种多样的精彩的手机功能,但是android手机如何实现打电话这个基本...

    Android发送邮件的方法实例详解

    本文实例讲述了Android发送邮件的方法。分享给大家供大家参考,具体如下: 在android手机中实现发送邮件的功能也是不可缺少的。如何实现它呢?下面以简单的例子进行说明。 程序如下: import java.util.regex....

Global site tag (gtag.js) - Google Analytics