null第6章 组件通信与广播消息 第6章 组件通信与广播消息 本章学习目标本章学习目标了解使用Intent进行组件通信的原理
掌握使用Intent启动Activity的方法
掌握获取Activity返回值的方法
了解Intent过滤器的原理与匹配机制
掌握发送和接收广播消息的方法
6.1 Intent简介6.1 Intent简介6.1 Intent简介 6.1 Intent简介 Intent是一个动作的完整描述,包含了动作的产生组件、接收组件和传递的数据信息
Intent也可称为一个在不同组件之间传递的消息,这个消息在到达接收组件后,接收组件会执行相关的动作
Intent为Activity、Service和BroadcastReceiver等组件提供交互能力
Intent的用途
启动Activity和Service
在Android系统上发布广播消息
广播消息可以是接收到特定数据或消息,也可以是手机的信号变化或电池的电量过低等信息6.1.1 启动Activity6.1.1 启动ActivityAndroid系统中,应用程序一般都有多个Activity,Intent可实现不同Activity之间的切换和数据传递
启动Activity方式
显式启动,必须在Intent中指明启动的Activity所在的类
隐式启动, Android系统根据Intent的动作和数据来决定启动哪一个Activity,也就是说在隐式启动时,Intent中只包含需要执行的动作和所包含的数据,而无需指明具体启动哪一个Activity,选择权由Android系统和最终用户来决定显式启动Activity显式启动Activity创建一个Intent
指定当前的应用程序上下文以及要启动的Activity
把创建好的这个Intent作为参数传递给startActivity()方法显式启动Activity示例(1)显式启动Activity示例(1)包含两个Activity
IntentDemoActivity
NewActivity
程序默认启动IntentDemoActivity
用户点击“启动Activity”按钮后,程序启动NewActivity
IntentDemo示例显式启动Activity示例(2)显式启动Activity示例(2)AndroidManifest.xml文件中注册两个Activity
注册Activity应使用
标签,嵌套在标签内部。IntentDemo示例AndroidManifest.xmlAndroidManifest.xmlIntentDemo示例AndroidManifest.xmlAndroidManifest.xml节点下有两个节点,分别代表应用程序中的IntentDemoActivity和NewActivityIntentDemo示例IntentDemoActivity.java文件(3)IntentDemoActivity.java文件(3)包含使用Intent启动Activity的核心代码:
Intent构造函数的第1个参数是应用程序上下文,在这里就是IntentDemoActivity;第2个参数是接收Intent的目标组件,即需要启动的ActivityIntentDemo示例隐式启动Activity隐式启动Activity好处:不需要指明需要启动哪一个Activity,而由Android系统来决定,这样有利于降低组件之间的耦合度
隐式启动Activity时, Android系统会在程序运行时解析Intent,并根据一定的规则对Intent和Activity进行匹配,使Intent上的动作、数据与Activity完全吻合
匹配的组件可以是程序本身的Activity,也可以是Android系统内置的Activity,还可以是第三方应用程序提供的Activity。
因此,这种方式强调了Android组件的可复用性。 隐式启动Activity隐式启动Activity如果程序开发人员希望启动一个浏览器,查看指定的网页内容,却不能确定具体应该启动哪一个Activity,可使用Intent的隐式启动方式,由Android系统在程序运行时决定具体启动哪一个应用程序的Activity来接收这个Intent
程序开发人员将浏览动作和Web地址作为参数传递给Intent,Android系统通过匹配动作和数据格式,找到最适合于此动作和数据格式的组件。隐式启动Activity隐式启动ActivityIntent的动作是Intent.ACTION_VIEW,数据是Web地址。使用Uri.parse(urlString)方法,字符串解释为Uri对象
Android系统匹配Intent时,先根据动作,得知需要启动具备浏览功能的Activity,但具体是浏览电话号码还是浏览网页,需要根据URI的数据类型来做最后判断。
因为数据提供Web地址"http://www.google.com",所以Intent最终启动具网页浏览功能的Activity
Android系统缺省调用内置的Web浏览器Intent的语法Intent的语法第1个参数是Intent需要执行的动作,Android系统支持的常见动作字符串常量可以参考表
第2个参数是URI,表示需要传递的数据
或者:
Intent的语法Intent的语法nullWebViewIntentDemo示例WebViewIntentDemo示例隐式启动Activity,用户界面
用户在文本框中输入Web地址后,点击“浏览此URL”按钮
WebViewIntentDemo示例WebViewIntentDemo示例程序根据用户输入的Web地址生成Intent以隐式启动的方式调用Android内置的Web浏览器,并打开指定的Web页面
本例输入Web地址http://www.google.com.hk,效果图:
6.1.2 获取Activity返回值6.1.2 获取Activity返回值很多情况下,后启动的Activity是为了让用户对特定信息进行选择,后启动的Activity关闭时,这些信息需要返回给先前启动的Activity
后启动的Activity称为为“子Activity”,先启动的Activity称为“父Activity”
如果子Activity的信息要返回父Activity,可以使用Sub-Activity的方式去启动子Activity
6.1.2 获取Activity返回值6.1.2 获取Activity返回值获取子Activity的返回值,一般可以分为以下三个步骤:
以Sub-Activity的方式启动子Activity
设置子Activity的返回值
在父Activity中获取返回值设置子Activity的返回值1设置子Activity的返回值1以Sub-Activity的方式启动子Activity
调用startActivityForResult(Intent, requestCode)
参数Intent用于决定启动哪个Activity
参数requestCode是请求码
所有子Activity返回时,父Activity都调用相同的处理函数,父Activity使用requestCode来确定数据由哪个子Activity返回以Sub-Activity的方式启动子Activity以Sub-Activity的方式启动子Activity显式启动子Activity的代码如下
隐式启动子Activity的代码如下 6.1.2 获取Activity返回值26.1.2 获取Activity返回值2设置子Activity的返回值
子Activity调用finish()函数关闭前,调用setResult()函数设定返回给父Activity的数据
setResult()的参数:
结果码:表明子Activity的返回状态
返回值:封装在Intent中,即子Activity通过Intent将需要返回的数据传递给父Activity。setResult()的参数setResult()的参数结果码
表明子Activity的返回状态,
通常为Activity.RESULT_OK(正常返回数据)或Activity.RESULT_CANCELED(取消返回数据)
也可以是自定义的结果码,结果码均为整数类型。
返回值:
封装在Intent中,即子Activity通过Intent将需要返回的数据传递给父Activity。
数据主要以Uri形式返回给父Activity
此外还可以附加一些额外信息,这些额外信息用Extra的集合表示。 设置子Activity的返回值代码设置子Activity的返回值代码以下代码说明如何在子Activity中设置返回值:6.1.2 获取Activity返回值36.1.2 获取Activity返回值3在父Activity中获取返回值
当子Activity关闭,父Activity调用onActivityResult(),获取子Activity的返回值
如果需要在父Activity中处理子Activity的返回值,则重载此函数即可。
onActivityResult()函数的语法:
第1个参数requestCode:请求码,用来判断第3个参数是哪个子Activity的返回值;
resultCode:表示子Activity的数据返回状态;
Data是子Activity的返回数据,返回数据类型是Intent。
根据返回数据的用途不同,Uri数据的
协议
离婚协议模板下载合伙人协议 下载渠道分销协议免费下载敬业协议下载授课协议下载
则不同,也可以使用Extra方法返回一些原始类型的数据。 父Activity中处理子Activity的返回值示例父Activity中处理子Activity的返回值示例代码的第1行和第2行是两个子Activity的请求码,在第7行对请求码进行匹配。父Activity中处理子Activity的返回值示例父Activity中处理子Activity的返回值示例对结果码进行判断
返回的结果码是Activity.RESULT_OK,则在代码的第10行使用getData()函数获取Intent中的Uri数据
如果返回的结果码是Activity.RESULT_CANCELED,则放弃所有操作ActivityCommunication示例ActivityCommunication示例以Sub-Activity方式启动子Activity,使用Intent进行组件间通信。ActivityCommunication示例ActivityCommunication示例当用户点击“启动Activity1”和“启动Activity2”按钮,程序分别启动SubActivity1和SubActivity2ActivityCommunication示例ActivityCommunication示例界面ActivityCommunication示例界面SubActivity1提供了一个输入框,以及“接受”和“撤销”两个按钮。
如果在输入框中输入信息后点击“接受”按钮,程序把输入框中的信息传递给其父Activity,并在父Activity的界面上显示。
如果用户点击“撤销”按钮,则程序不会向父Activity传递任何信息。
SubActivity2仅提供用于关闭SubActivity2的“关闭”按钮。
用于说明如何在父Activity中处理多个子ActivityActivityCommunication示例文件结构ActivityCommunication示例文件结构父Activity:
代码:ActivityCommunication.java
界面布局:main.xml
两个子Activity:
代码分别是SubActivity1.java和SubActivity2.java
界面布局分别在subactivity1.xml和subactivity2.xml中。 ActivityCommunicationActivity.javaActivityCommunicationActivity.java分别定义两个子Activity的请求码ActivityCommunication示例ActivityCommunicationActivity.javaActivityCommunicationActivity.java以Sub-Activity的方式分别启动两个子Activity。ActivityCommunication示例ActivityCommunicationActivity.javaActivityCommunicationActivity.java在父Activity中获取返回值ActivityCommunication示例ActivityCommunicationActivity.javaActivityCommunicationActivity.java子Activity关闭后的返回值处理函数,其中requestCode是子Activity返回的请求码;resultCode是结果码ActivityCommunication示例ActivityCommunicationActivity.javaActivityCommunicationActivity.java对结果码进行判断,如果等于RESULT_OK,获取子Activity返回值中的数据;data是返回值,子Activity需要返回的数据就保存在data中。
ActivityCommunication示例SubActivity1和SubActivity2功能SubActivity1和SubActivity2功能ActivityCommunication示例SubActivity1.javaSubActivity1.javaActivityCommunication示例SubActivity1.javaSubActivity1.java将EditText控件内容数据保存在Uri,并构造Intent
RESUIT_OK作为结果码,通过setResult()函数,将result设定为返回值。
调用finish()函数关闭当前的子Activity
ActivityCommunication示例SubActivity1.javaSubActivity1.java将EditText控件内容数据保存在Uri,并构造Intent
RESUIT_CANCELED作为结果码,通过setResult()函数,将result设定为返回值。
调用finish()函数关闭当前的子Activity
ActivityCommunication示例SubActivity2.javaSubActivity2.javasetResult()函数仅设置了结果码,第2个参数为null,表示没有数据需要传递给父ActivityActivityCommunication示例intent 复习intent 复习null例1.1null例1.2null例1.3null例2.1nullIntent发送者设定Action来说明将要进行的动作,而Intent的接收者在AndroidManifest.xml文件中通过设定Intent Filter来声明自己能接收哪些Intent例2.16.2 Intent过滤器6.2 Intent过滤器6.2 Intent过滤器6.2 Intent过滤器Intent解析
隐式启动Activity时,并没有在Intent中指明Activity所在的类,Android 如何知道哪个应用程序(和组件)能用来响应这个请求呢?
因此,Android系统一定存在某种匹配机制,使Android系统能够根据Intent中的数据信息,找到需要启动的Activity。
这种匹配机制是依靠Android系统中的Intent过滤器(Intent Filter)来实现的。6.2 Intent过滤器6.2 Intent过滤器使用Intent Filter,应用程序组件告诉Android ,它们能为程序组件的动作请求提供服务,包括同一个程序的组件、本地的或第三方的应用程序。
为了注册一个应用程序组件为 Intent 处理者,在组件的 manifest 节点添加一个 intent-filter 标签。
在 Intent Filter 节点里,你能指定组件支持的动作、种类和数据
应用程序的Activity、Service和BroadcastReceiver组件都可以注册Intent过滤器6.2 Intent过滤器6.2 Intent过滤器Intent过滤器是根据Intent中的动作(Action)、类别(Categorie)和数据(Data)等内容,对适合接收该Intent的组件进行匹配和筛选的机制
Intent过滤器可以匹配数据类型、路径和协议,还可确定多个匹配项顺序的优先级(Priority)
应用程序的Activity、Service和BroadcastReceiver组件都可以注册Intent过滤器。这样,这些组件在特定的数据格式上则可以产生相应的动作。 6.2 Intent过滤器6.2 Intent过滤器为了使组件能够注册Intent过滤器,通常在AndroidManifest.xml文件的各个组件下定义节点,然后在节点中使用标签,声明该组件所支持的动作、执行的环境和数据格式等信息。
也可在程序代码中动态为组件设置Intent过滤器
节点支持标签、标签和标签,分别用来定义Intent过滤器的“动作”、“类别”和“数据”。
节点支持的标签和属性说明参考表 节点节点一条元素至少包含一个,否则任何Intent请求都不能和该匹配
使用 android:name 特性来指定对响应的动作名
动作名必须是独一无二的字符串,好习惯是使用基于 Java 包的命名方式的命名系统。
如果Intent请求的Action和中个某一条匹配,那么该Intent就通过了这条的动作测试。
如果Intent请求或中没有说明具体的Action类型,那么:
(1) 如果中没有包含任何Action类型,那么无论什么Intent请求都无法和这条匹配;
(2) 如果Intent请求中没有设定Action类型,那么只要中包含有Action类型,这个Intent请求就将顺利通过行为测试标签标签标签指定Intent过滤器的服务方式,用来指定在什么样的环境下动作才被响应。
只有当Intent请求中所有的Category与组件中某一个IntentFilter的完全匹配时,才会让该 Intent请求通过测试
IntentFilter中多余的声明不导致匹配失败
一个没有指定任何类别测试的 IntentFilter仅仅只会匹配没有设置类别的Intent请求
每个Intent过滤器可以定义多个标签,程序开发人员可以使用自定义的类别,或使用Android系统提供的类别
Android系统提供的类别可以参考表 标签标签标签标签允许你指定组件能作用的数据的匹配指定希望接受的Intent请求的数据URI和数据类型。
URI被分成三部分来进行匹配:scheme、 authority和path。
用setData()设定的Intent请求的URI数据类型和scheme必须与IntentFilter中所指定的一致
若IntentFilter中还指定了authority或path,它们也需要相匹配才会通过测试。
URI示例URI示例content://com.example.project:200/folder/subfolder/etc
scheme为"content"
host为"com.example.project"
port为"200"
path为"folder/subfolder/etc"
host和port一起组成了URI authority
如果host未指定,则port被忽略.这些属性都是可选的,但它们并非相互独立:要使一个authority有意义,必须指定一个scheme;要使一个path有意义, 必须指定一个scheme和一个authority
当intent对象中的URI和intent filter中相比较时,它只和filter中定义了的部分比较
eg. 如果filter中定义scheme,那么所有包含该scheme的URI的intent对象都通过测试
元素的type属性指定了数据类型。它在filter中比在URI中更常见。
intent对象和filter都可以使用"*"通配符作为子类型,例如"text/*" "audio/*"表示所有的子类型都匹配匹配规则匹配规则1、一个不含uri也不含数据类型的intent对象只通过两者都不包含的filter
2、一个含uri但不含数据类型的intent对象(并且不能从uri推断数据类型的)只能通过这样的filter:uri匹配, 并且不指定类型
eg. 类似mailto:和tel:这样不指定实际数据的uri
3、一个只包含数据类型但不包含URI的intent只通过这样的filter:该filter只列出相同的数据类型, 并且不指定uri匹配规则匹配规则4、一个既包含uri又包含数据类型的intent对象只通过这样的filter:intent对象的数据类型和filter中的一个类型匹配,intent对象的uri要么和filter的uri匹配,要么intent对象的uri为content:或者file:,并且filter不指定uri
组件常可以从文件和content provider中获取数据。因此,它们的filter可以只列出数据类型不列scheme
告诉android:该组件可以取图像数据
由于大部分可用的数据由content provider提供, 指定数据类型但不指定uri的filter是最常见的情况.匹配规则匹配规则另一常见配置是filter具有一个scheme和一个数据类型
eg. 下列元素告诉android该component可以从网络获取图像数据并显示之:
考虑用户点击一个网页时浏览器的动作:它首先试图显示这个数据(当做html页处理)。如果无法显示,则创建一个隐式intent, 并启动一个可以处理它的activity。如果没有这样的activity,那么它请求下载管理器来下载该数据。然后将数据置于一个content provider的控制之下,这样有很多activity(拥有只有数据类型的filter)可以处理这些数据匹配规则匹配规则大部分应用程序还有一种单独启动、不需要引用任何特定的数据。
这些能启动应用程序的activity具有action为"android.intent.action.MAIN" 的filter。
如果它们需要在应用程序启动器中显示,它们必须指定"android.intent.category.LAUNCHER" 的category匹配规则匹配规则
如果一个intent可以通过多于一个activity或者service的filter,那么用户可能会被询问需要启动哪一个
如果一个都没有的话,那么会抛出异常6.2 Intent过滤器6.2 Intent过滤器intent filter的名字很形象
过滤掉不想接受的intent,留下想接受的intent
显式intent无视intent filter
一个组件对能做的每件事有单独的filter
记事本程序的NoteEditor activity有两个filter
一个启动并显示一个特定的记录给用户查看或编辑
另一个启动一个空的记录给用户编辑.Intent解析Intent解析Intent解析是Intent到Intent过滤器的映射过程
Intent解析可以在所有的组件中,找到一个可以与请求的Intent达成最佳匹配的Intent过滤器
Android系统中Intent解析的匹配规则如下: Intent解析Intent解析(1) Android系统把所有应用程序包中的Intent过滤器集合在一起,形成一个完整的Intent过滤器列表
(2) 在Intent与Intent过滤器进行匹配时,Android系统会将列表中所有Intent过滤器的“动作”和“类别”与Intent进行匹配,任何不匹配的Intent过滤器都将被过滤掉。没有指定“动作”的Intent过滤器可以匹配任何的Intent,但是没有指定“类别”的Intent过滤器只能匹配没有“类别”的Intent
(3) 把Intent数据Uri的每个子部与Intent过滤器的标签中的属性进行匹配,如果标签指定了协议、主机名、路径名或MIME类型,那么这些属性都要与Intent的Uri数据部分匹配,任何不匹配的Intent过滤器均被过滤
(4) 如果Intent过滤器的匹配结果多于一个,则根据在标签中定义的优先级标签来对Intent过滤器进行排序,选择优先级最高的Intent过滤器AndroidManifest.xml文件AndroidManifest.xml文件注册Intent过滤器,设置节点属性来捕获指定的IntentIntentResolutionDemo示例AndroidManifest.xml文件AndroidManifest.xml文件注册Intent过滤器,设置节点属性来捕获指定的IntentIntentResolutionDemo示例AndroidManifest.xml文件AndroidManifest.xml文件注册Intent过滤器,设置节点属性来捕获指定的IntentIntentResolutionDemo示例AndroidManifest.xml文件AndroidManifest.xml文件Activity的Intent过滤器,动作是android.intent.action.MAIN,类别是android.intent.category.LAUNCHER
由此可知,这个Activity是应用程序启动后显示的缺省用户界面。IntentResolutionDemo示例AndroidManifest.xml文件AndroidManifest.xml文件Activity的Intent过滤器,动作是android.intent.action.VIEW
表示根据Uri协议,以浏览的方式启动相应的Activity
类别是android.intent.category.DEFAULT
表示数据的默认动作
数据的协议部分是android:scheme="schemodemo"
数据的主机名称部分是android:host="edu.hrbeu"。 IntentResolutionDemo示例IntentResolutionDemo.javaIntentResolutionDemo.java定义了一个Intent用来启动另一个Activity
这个Intent与Activity设置的Intent过滤器匹配
文件中Intent实例化和启动Activity的代码IntentResolutionDemo示例6.2 Intent过滤器6.2 Intent过滤器定义Intent,动作为Intent.ACTION_VIEW,与Intent过滤器的动作android.intent.action.VIEW匹配
Uri是“schemodemo://edu.hrbeu/path”,其中的协议部分为“schemodemo”,主机名部分为“edu.hrbeu”,也与Intent过滤器定义的数据要求完全匹配
因此,代码定义的Intent,在Android系统与Intent过滤器列表进行匹配时,会与AndroidManifest.xml文件中ActivityToStart定义的Intent过滤器完全匹配IntentResolutionDemo示例IntentResolutionDemo示例IntentResolutionDemo示例AndroidManifest.xml中每个组件的被解析成一个Intent过滤器对象
当应用程序安装到Android系统时,所有的组件和Intent过滤器都会注册到Android系统中。
这样,Android系统便可以将任何一个Intent请求通过Intent过滤器映射到相应的组件上。 6.3 广播消息6.3 广播消息6.3 广播消息6.3 广播消息Intent的另一种用途是发送广播消息,应用程序和Android系统都可以使用Intent发送广播消息,广播消息的内容可以与应用程序密切相关的数据信息,也可以Android的系统信息,例如网络连接变化、电池电量变化、接收到短信或系统设置变化等。
如果应用程序注册了BroadcastReceiver,则可以接收到指定的广播消息。
使用Intent发送广播消息非常简单,只需创建一个Intent,并调用sendBroadcast()函数就可把Intent携带的信息广播出去。
但需要注意的是,在构造Intent时必须定义一个全局唯一的字符串,用来标识其要执行的动作,通常使用应用程序包的名称。
如果要在Intent传递额外数据,可以用Intent的putExtra()方法。下面的代码构造用于广播消息的Intent,并添加了额外的数据,然后调用sendBroadcast()发送广播消息:sendBroadcast()代码sendBroadcast()代码
BroadcastReceiver用于监听广播消息
可以在AndroidManifest.xml文件或在代码中注册一个BroadcastReceiver,并使用Intent过滤器指定要处理的广播消息。onReceive()方法onReceive()方法创建BroadcastReceiver需继承BroadcastReceiver类,并重载onReceive()方法
示例代码如下:onReceive()方法onReceive()方法当Android系统接收到与注册BroadcastReceiver匹配的广播消息时,Android系统会自动调用这个BroadcastReceiver接收广播消息
在BroadcastReceiver接收到与之匹配的广播消息后,onReceive()方法会被调用,但onReceive()方法必须要在5秒钟执行完毕,否则Android系统会认为该组件失去响应,并提示用户强行关闭该组件BroadcastReceiverDemo示例BroadcastReceiverDemo示例在应用程序中注册BroadcastReceiver组件,并指定接收广播消息的类型
界面如图所示
点击“发生广播消息”按钮后,EditText控件中内容将以广播消息的形式发生出去,示例内部的BroadcastReceiver将接收这个广播消息,并显示在用户界面的下方。 BroadcastReceiverDemo.javaBroadcastReceiverDemo.java文件中包含发送广播消息的代码,其关键代码如下 BroadcastReceiverDemo示例BroadcastReceiverDemo.javaBroadcastReceiverDemo.java创建了一个节点,声明了Intent过滤器的动作为“edu.hrbeu.BroadcastReceiverDemo”,
这与BroadcastReceiverDemo.java文件中Intent的动作一致,表明这个BroadcastReceiver可以接收动作为“edu.hrbeu.BroadcastReceiverDemo”的广播消息 BroadcastReceiverDemo示例MyBroadcastReceiver.javaMyBroadcastReceiver.java创建了一个自定义的BroadcastReceiver:
首先继承了BroadcastReceiver类,并重载onReveive()
当接收到AndroidManifest.xml文件定义的广播消息后,程序将自动调用onReveive()函数进行消息处理
通过调用getStringExtra()函数,从Intent中获取标识为message的字符串数据,并使用Toast()函数显示信息BroadcastReceiverDemo示例习题:习题:简述Intent的定义和用途。
简述Intent过滤器的定义和功能。
简述Intent解析的匹配规则
编程实现具有“登录”按钮的主界面,点击“登录”按钮后打开一个新的Activity,新打开的Activity上面有输入用户名和密码的控件,在用户关闭这个Activity后,将用户名和密码传递到主界面的Activity中。