每个应用程序都有若干个Activity组成,每一个Activity都是一个应用程序与用户进行交互的窗口,呈现不同的交互界面。因为每一个Acticity的任务不一样,所以经常互在各个Activity之间进行跳转,在Android中这个动作是靠Intent来完成的。你通过startActivity()方法发送一个Intent给系统,系统会根据这个Intent帮助你找到对应的Activity,即使这个Activity在其他的应用中,也可以用这种方法启动它。
Intent是Android系统用来抽象描述要执行的一个操作,也可以在不同组件之间进行沟通和消息传递。
Intent意图可以是明确的指定组件的名称,这样你可以精确的启动某个系统组件,比如启动一个Activity。它也可以是模糊的,没有指定组件名称,只要是能够匹配到这个Intent的应用都可以接收到,比如发送一个拍照Intent,所有的拍照应用都会响应。
显式的Intent就是你已经知道要启动的组件名称,比如某个Activity的包名和类名,在Intent中明确的指定了这个组件(Activity),一般来说这种Intent经常用在一个应用中,因为你已经明确的知道要启动的组件名称。
隐式的Intent就是你不知道要启动的组件名称,只知道一个Intent动作要执行,比如:拍照,录像,查看地图。一般来说这种Intent用在不同的应用之间传递信息。
当你创建一个显式Intent来启动一个Activity或者Service时,系统会立刻启动那个组件通过你的Intent对象。
当你创建一个隐式Intent,系统会根据manifest file中的intent filter找匹配的组件,如果你发送的Intent匹配到一个intent filter,系统会把你的Intent传递给该filter对应的组件(Activity、Service等),并且启动它。如果找到多个匹配的intent filter对应的应用程序,则会弹出一个对话框让你选择哪个应用程序接受你的Intent。
注:1、intent filter是一种应用程序manifest文件中的语法表达,就像是html的标签,它是一个系统组件标签(比如:Activity)的组成部分,可以说是子标签吧,这个系统组件接受什么样的intent就是用它来指定的,如果一个系统组件不写intent filter,那么它只能通过显式的intent来启动。2、出于安全的角度,你的Service组件务必不要用隐式的intent filter来进行说明,因为用隐式的intent启动一个Service往往不能保证Service会被启动,并且用户也不知道哪个Service会响应你的Intent。从Android5.0(API 21),系统会抛出异常当你用隐式的Intent去调用bindService()方法。
Android系统通过Intent对象携带的信息来确定启动哪个系统组件,比如:准确的组件名称,哪一个类别的组件会接收到这个intent,Intent还会携带其他的信息以便于组件正确的执行action。一个Intent主要包含以下信息:
要启动的组件名称,在创建Intent的时候是可选的,但是它是显式Intent的重要标志,有它就意味着只有Component name匹配上的那个组件才能接收你发送出来的显示intent。如果不写那么你创建的Intent就是隐式的,系统会根据这个intent的其他信息(比如:action、data、category)来确定哪些组件来接收这个intent,所以如果你想明确的启动哪个组件,就通过component name来指定。
Intent的ComponentName属性是一个类的全称,包括包名,比如:com.example.ExampleActivity,你可以通过Intent的setComponent(),setClass(),setClassName()方法来设定,也可以通过Intent的构造方法来设定。
意图,一个字符串变量,用来指定Intent要执行的动作类别(比如:view or pick)。你可以在你的应用程序中自定义action,但是大部分的时候你只使用在Intent中定义的action。下面是启动Activity经常用的action:
在调用startActivity()方法启动Activity时,用此action来呈现一些信息给用户,比如在相册中查看一张照片,显示一个地理位置在地图中。
也被称为"share"(共享)意图,在调用startActivity()方法启动Activity时,用此action来分享一些用户想要分享的数据给其他应用程序,比如邮件app或者社交app。
想要了解更多的action可以查看Intent源码或者api,在Intent中定义了很多action,除了在Android framework中,在别处也定义了很多action,比如在Settings应用中。
你可以通过Intent的setAction()方法或者Intent的构造方法来指定action。如果你要自定义action,最好是用你的包名做前缀,比如:
static final String ACTION_TIMETRAVEL = "com.example.action.TIMETRAVEL";
一个Uri对象,对应着一个数据,这个数据可能是MIME类型的。当创建一个intent时,除了要指定数据的URI之外,指定数据的类型(MIME type)也很重要,比如,一个activity能够显示照片但是无法播放视频,虽然启动Activity时URI格式很相似。指定MIME type是很重要的,它能够帮助系统找到最合适的那个系统组件来处理你的intent请求。然而,MIME type有时能够通过URI来推测出来,特别是当data是content:的URI,这样的data表明在设备中由ContentProvider提供。
只设置数据的URI可以调用setData()方法,只设置MIME类型可以调用setType()方法,如果要同时设置这两个可以调用setDataAndType()。
注意:如果要设置URI和MIME,不要调用setData()和setType(),因为会相互清除设置的参数数据,而是直接调用setDataAndType()。
一个包含Intent额外信息的字符串,表示哪种类型的组件来处理这个Intent。任何数量的Category 描述都可以添加到Intent中,但是很多intent不需要category,下面列举一些常用的category:
目标Activity允许从web页面上的链接(比如图片链接)启动来显示数据。
表示这个Activity是Activity栈最初的Activity,应用程序的主Activity,可以在桌面应用程序列表找到并启动它。
你可以通过调用addCagegory()方法来设置category。
以上Intent的属性(component name、action、data and category)都是Intent的特征属性,通过这些属性Android系统可以找到哪个应用组件将会被启动。
以下的属性是Intent的额外属性,这些属性不会影响到intent的处理和启动系统组件。
Intent可以携带的额外key-value数据,你可以通过调用putExtra()方法设置数据,每一个key对应一个value数据。你也可以通过创建Bundle对象来存储所有数据,然后通过调用putExtras()方法来设置数据。对于数据key的名字要尽量用包名做前缀,然后再加上其他,这样来保证key的唯一性。
用来指示系统如何启动一个Activity(比如:这个Activity属于哪个Activity栈)和Activity启动后如何处理它(比如:是否把这个Activity归为最近的活动列表中)。
一个显式Intent明确的指定了要启动的组件名称,比如Activity名称或者Service的名称。创建一个显式的Intent必须定义Component属性,其他的属性可选。下面的例子是创建一个Service在app中,名字叫DownloadService,功能是从网络上下载文件,你可以通过下面的代码来启动它:
// Executed in an Activity, so 'this' is the Context // The fileUrl is a string URL, such as "http://www.example.com/image.png" Intent downloadIntent = new Intent(this, DownloadService.class); downloadIntent.setData(Uri.parse(fileUrl)); startService(downloadIntent);
一个隐式的Intent定义了将要执行的动作,任何在设备上的app都可以响应这个动作。用隐式Intent的非常的有用,当你的app不能处理某些请求动作时,但是系统中的其他应用有这个处理的能力,用户就能方便的利用其他应用完成这个操作。比如你用百度云盘下载了一个pdf文档,你在点击打开这个文档的时候百度云盘是无法打开的,但是也许你系统上安装有其他的能打开pdf文档的阅读器,这个时候就会弹出一个对话框,列举了可以打开pdf文档的应用程序,你可以自由选择一个应用程序打开你下载的文档。例如下面查看文档的例子:
// Create the text message with a string Intent sendIntent = new Intent(); sendIntent.setAction(Intent.ACTION_SEND); sendIntent.putExtra(Intent.EXTRA_TEXT, textMessage); sendIntent.setType(HTTP.PLAIN_TEXT_TYPE); // "text/plain" MIME type // Verify that the intent will resolve to an activity if (sendIntent.resolveActivity(getPackageManager()) != null) { startActivity(sendIntent); }
注意:也许你的设备中没有能够执行你的隐式Intent的应用,这个时候startActivity将会失败并且你的app会出现crash,最好的办法是在startActivity之前调用resolveActivity检查一下是否有Activity可以响应。如果系统中有一个应用程序可以响应则会直接打开那个应用程序,如果系统中有多个app可以处理这个action则会弹出对话框让你选择哪个应用程序来处理。
以上内容主要说了Intent的定义、分类和属性解释,这样让你对Intent有一个详细的了解,为以后学习利用Intent在应用程序之间进行交流打下基础,下一篇博客将会给大家聊聊Intent的用法。
本文属原创,转载请注明出处,违者必究
关注微信公众平台:程序员互动联盟(coder_online),你可以第一时间获取原创技术文章,和(java/C/C++/Android/Windows/Linux)技术大牛做朋友,在线交流编程经验,获取编程基础知识,解决编程问题。程序员互动联盟,开发人员自己的家。