`

Intent和Broadcast面对面

阅读更多

 

4  Intent Broadcast 面对面

在第 3 章介绍了 Android 应用的核心组件: Activity, Service Broadcast receiver ,这些组件通过消息的机制联系起来,承载这个消息的组件是 Intent Broadcast 也可以完成这个通信的任务。不过 Broadcast 只能发给合适的 Broadcast Receiver 。他们最大的特色是可以解耦,使各功能模块独立。

本章我们将从基本理论介绍开始,深入分析个中原理,再以例子的形式详解 Intent Broadcast 的运用。主要内容框架如下:

4.1   Android 应用程序的核心 ——Intent

4.2  Android Intent 解析

4.3  利用 Intent 来广播 (Broadcast) 事件

4.4  应用实例详解

 

4.1  Android 应用程序的核心 ——Intent

Intent 是一种运行时绑定( runtime binding )机制,它能在程序运行的过程中连接两个不同的组件。 Intent 包含一个执行操作的抽象数据结构,这个数据结构用于传递给执行操作的组件,或者,常见于 broadcast 的情况,用于描述正在执行或者已经发生的事情。对于第 3 章中介绍的三种组件,有独立的传送 intent 的机制

·       Activity 创建新的活动或者让一个现有的 Activity 执行新的任务,可以通过调用传递 intent Context.startActivity() Activity.startActivityForRestult() 方法来达成。

·       Service 启动一个新的服务,或者向一个已有的服务传递新的指令,可以调用 Context.startService() Context.bindService() 方法,此方法的将上下文对象 context Service 绑定。

·       Broadcast Receiver 通过 Context.sendBroadcast() Context.sendOrderBroadcast() Context.send-StickBroadcast() 这三个方法可以发送 BroadcastIntent BroadcastIntent 发送后,所有已注册的拥有与之相匹配 IntentFilter BroadcastReceiver 就会被激活。这种机制被广泛运用于设备或系统状态变化的通知,一个常见的例子是,当 Android 的电池电量过低时,系统会发送 Action BATTERY_LOW 的广播,接着任何可匹配该 Action IntentFilter 注册的 BroadcastReceiver 都会各自运行自定义的处理代码,比如关闭设备的 WIFI GPS 以节省电池消耗。

在每种情况下, Android 系统查找合适的 activity service broadcast receivers 来响应意图,如果有必要的话,初始化他们。这些消息系统之间没有重叠,即广播意图仅会传递给广播接收者,而不会传递活动或服务,反之亦然。

 

4.1.1  Intent 的组成


Android
中提供了
Intent
机制来协助应用间的交互与通讯,
Intent
负责对应用中一次操作的动作、动作涉及数据、附
加数据进行描述,

Android
则根据此
Intent
的描述,负责找到对应
的组件,将
Intent
传递给调用的组件,并完成组件的调用。
Intent
不仅可用于
应用程序之间,也可用于应用程序内部的
Activity/Service
之间的交互。因此,
Intent
在这里起着一个媒体中介的作
用,专门提供组件互相调用的相关信息,实现调用者与被调用者之间的解耦。


简而言之, Intent 就是组合一定的信息,然后传达这些信息给特定的对象,或者广播一些信息某些对象;这里涉及两方面的内容:

A) 消息的发送;

B)    消息的接收;

完成这些神奇的功能, Intent 需要什么样的结构,由哪些零件组成呢?

Intent 这个神奇的组件很抽象,是一个抽象的信息捆绑结构,在这个结构中发挥作用的基本零件可以分为组件名称 (Component Name) 、动作( Action )、数据( Data )、类型( Category )、附加信息( Extra )和标识位( Flag 6 部分,下面是详细介绍。

4.1.1.1   Intent 的组件名称( Component Name)

组件名称是 Intent 目标组件的名称。组件名称是一个 ComponentName 对象,这种对象名称是目标组件类名和目标组件所在应用程序的包名的组合。 Android 系统匹配目标组件有两种方式:

A.  


显示
Intent
:对于明确指出了目标组件名称的


Intent
(调用
setComponent()
方法或
setClass()
方法来指定)。


B.  


隐式
Intent
:对于没有明确指出目标组件名称的
Intent
。
隐式
Intent
,由于没有明确的目标组件名称,所以必须包含足够的属性信息,他们是:
Action

Data

Category
。再
由
Android
系统帮助应用程序寻找与
Intent
请求意图最匹配的组件。

所以,设置 Intent Component 定义了 Android 系统匹配目标组件的显示方法。

4.1.1.2   Intent 的动作( Action

                  Action 描述 Intent 所触发动作名字的字符串,对于 BroadcastIntent 来说, Action 指被广播出去的动作。理论上 Action 以为任何字符串,而与 Android 系统应用有关的 Action 字符串以静态字符串常量的形式定义在了 Intent 类中。表 4-1 列出了当前 Android 系统中常见的部分 Activity Action Intent Action ,以供参考。

4-1 Android 常用部分 Action

4.1.1.3   Intent 的数据( Data


Data, 
就是
Action
所要操作的数据。
Android
中采用指向数据的一个
URI
来表示,如在联系人应用中,一个指向某联
系人的
URI
可能为:
content://contacts /1
。对于不同的动作,其
URI
数据的类型是不同的(可以设置
type
属性指
定特定类型数据),如
ACTION_EDIT
指定
Data
为文件
URI
,打电话为
tel:URI
,访问网络为
http:URI
,而由

content provider
提供的数据则为
content: URIs



                  正确设置 Intent 的数据对于 Android 寻找系统中匹配 Intent 请求的组件很重要。设置的精确可以提高效率,设置错了,得出的数据牛头不对马嘴,甚至程序会崩溃。

4.1.1.4   Intent 的类型( Category

                  Category 是对被请求组件的额外描述信息 Android 也在 Intent 类中定义了一组静态字符串常量表示 Intent 不同的类别,表 4-2 列出了 Android 系统中常见的部分 Category 常量。

4-2 Android 系统中常见的部分 Category 常量

4.1.1.5   Intent 的附加信息( Extra

            Extra 当我们使用 Intent 连接不同的组件时,有时需要在 Intent 中附加额外的信息,以便将数据传递给目标 Activity 。比如 ACTION_TIMEZONE_CHANGED 需要带有附加信息表示新的时区。

Extra 用键值对结构保存在 Intent 对象当中, Intent 对象通过调用方法 putExtras() getExtras() 来存储和获取 Extra Extra 是以 Bundle 对象的形式来保存的, Bundle 对象提供了一系列 put get 方法来设置、提取相应键值信息。在 Intent 类中同样为 Android 系统应用的一些 Exrta 的键值定义了静态的字符串常量。如图 4-3

4-3 Extra 部分常量

 

 

 

4.1.1.6   Intent 的标识位( Flag

                 

Intent 的标识位( Flag )是 Android 的过滤的核心组件,决定了启动的目标组件的方式。即告诉 Android 系统如何启动一个 Activity 及如何执行 Actvity 的任务。在 Intent 类中同样为 Android 系统应用的一些 Flag 的键值定义了静态的字符串常量。如图 4-4

                                                                             4-4 Flag 部分常量表

4.2 Android Intent 解析

前面提到, Android 使用 Intent 有显式和隐式两种方式:

显示的方式,是定义 Intent 对象,然后通过调用 setComponent 接口设置目标组件的 Component name, 如下代码所示:

Intent intent =  new Intent();

Intent.setComponent(this.getComponentName());

隐式的方式,就是在代码中没有明确声明启动哪个组件,而是通过 IntentFilter 过滤筛选出目标组件。

     那么 IntentFilter 是个啥东西呢? IntentFilter 是描述组件所能响应的 Intent 的一个属性组合,具体就是说明组件希望接收什么类型的请求,处理什么类型的数据,以什么方式处理等。 应用程序的组件为了告诉Android 自己能响应、处理哪些隐式Intent 请求,可以声明一个甚至多个IntentFilter

IntentFilter 在应用开发的过程中,主要是在 Android-Manifest.xml 声明,具体形式如下:

<intent-filter>

        <action android:name="android.intent.action.MAIN" />

        <category android:name="android.intent.category.LAUNCHER" />

</intent-filter>

<intent-filter>

          <action android:name="android.intent.action.VIEW" />

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

         <category android:name="android.intent.category.BROWSABLE" />

          <data android:scheme="myapp" android:host="oauth" />

</intent-filter>

 

隐式 Intent IntentFilter 进行比较时的三要素: Action Data Category

一个隐式 Intent 请求要能够传递给目标组件,必需通过以上三个方面的检查。如果任何一方面不匹配, Android 都不会将该隐式 Intent 传递给目标组件。

Android 解析 Intent 的详细过程如下图 4-5

 

4-5 Android 解析 Intent 的详细过程

Note: 在通过和 IntentFilter 比较来解析隐式 Intent 请求时, Android 将以下三个因素作为选择的参考标准。 Action Data Category 。而 Extra Flag 在解析收到 Intent 时是并不起作用的。

v  Action 解析

<intent-filter> 元素中可以包括子元素 <action> ,一条 <intent-filter> 元素至少应该包含一个 <action> ,否则任何 Intent 请求都不能和该 <intent-filter> 匹配。

如果 Intent 请求的 Action <intent-filter> 中个某一条 <action> 匹配,那么该 Intent 就通

过了这条 <intent-filter> 的动作测试。

如果 Intent 请求或 <intent-filter> 中没有说明具体的 Action 类型,那么会出现下面两种情况。

  1. 如果 <intent-filter> 中没有包含任何 Action 类型,那么无论什么 Intent 请求都无法和这条 <intent-filter> 匹配。
  2. 反之,如果 Intent 请求中没有设定 Action 类型,那么只要 <intent-filter> 中包含有 Action 类型,这个 Intent 请求就将顺利地通过 <intent-filter> 的行为测试。

v  Data 解析

数据在 <intent-filter> 中的描述如下:

<data> 元素指定了希望接受的 Intent 请求的数据 URI 和数据类型, URI 被分成三部分来进行匹配: scheme authority path 。其中,用 setData() 设定的 Intent 请求的 URI 数据类型和 scheme 必须与 IntentFilter 中所指定的一致。若 IntentFilter 中还指定了 authority path ,它们也需要相匹配才会通过测试。

v  Category 解析

<intent-filter> 元素可以包含 <category> 子元素,比如:只有当 Intent 请求中所有的 Category 与组件中某一个 IntentFilter <category> 完全匹配时,才会让该 Intent 请求通过测试, IntentFilter 中多余的 <category> 声明并不会导致匹配失败。一个没有指定任何类别测试的 IntentFilter 仅仅只会匹配没有设置类别的 Intent 请求。

Note: 显式 Intent 直接用组件的名称定义目标组件,这种方式很直接。显式 Intent 多用于在应用程序内部传递消息。比如在某应用程序内,一个 Activity 启动一个 Service 。隐式 Intent 恰恰相反,由于开发人员往往并不清楚别的应用程序的组件名称,它不会用组件名称定义需要激活的目标组件,它更广泛地用于在不同应用程序之间传递消息。

 

4.3 利用 Intent 来广播 (Broadcast) 事件

Android 系统中,广播( Broadcast )是在组件之间传播数据( Intent )的一种消息机制;这些组件甚至是可以位于不同的进程中,这样它就像 Binder 机制一样,起到进程间通信的作用。

         Android 系统中,为什么需要广播机制呢?广播机制,本质上它就是一种组件间的通信方式,如果两个组件位于不同的进程当中,那么可以用 Binder 机制来实现,如果两个组件是在同一个进程中,那么它们之间可以用来通信的方式就更多了,这样看来,广播机制似乎是多余的。然而,广播机制却是不可替代的,它和 Binder 机制不一样的地方在于,广播的发送者和接收者事先是不需要知道对方的存在的,这样带来的好处便是,系统的各个组件可以松耦合地组织在一起,这样系统就具有高度的可扩展性,容易与其它系统进行集成。

广播在 Android 系统中无处不在,为了方便应用程序处理广播, Android 提供了很多 Action, 应用程序可以直接接收甚至发出这些 Action 。下图 4-6 是部分常量:

4-6 Broadcast 系统部分常量

4.3.1 Broadcast 的广播流程

Broadcast 的广播在 Android 系统中有一个标准的流程。

首先,定义自己的广播接收器,这里需要设置广播的 Action Category 等信息。

其次,注册 broadcast, 这里有两种注册方式,静态和动态注册。这两种注册方式的区别是,静态注册是常驻型广播,它的生命周期跟宿主 Activity 的生命周期脱离,即程序关闭之后,如果有信息广播来,程序也会被系统调用自动运行;动态注册不是常驻型广播,它的生命周期跟宿主 Activity 的生命周期一致,即程序关闭后,广播的生命周期也结束了,即使有广播信息来,系统也不会自动调用程序。具体实现方式后面讨论。

其三,在需要发送信息的地方,把要发送的信息和用于过滤的信息(如 Action Category )装入一个 Intent 对象,然后通过调用 Context.sendBroadcast() Context.sendOrderBroadcast() Context.sendstickyBroadcast() 方法,把 Intent 对象以广播的方式发出去。

其四,筛选 Broadcast receiver 。这个过程类似于 IntentFilter 的过程,完全由 Android framework 层完成。通过 Action 等属性,合适的 Broadcast 接收器会被筛选出来。

最后, BroadcastReceiver void onReceive(Context curContext, Intent broadcastMsg) 方法会被调用。处理消息的内容,执行相应的操作。这个方法返回后 BroadcastReceiver 就停止了。

            具体的过程,可以参考图 4-7 广播流程图

 

4-7 广播流程图

4.3.2 Broadcast 的实现过程

 

            这里介绍 Broadcast 的实现过程的框架,以理清 Broadcast 的使用逻辑。

                  首先,定义一个广播接收器,继承自 BroadcastReceiver, 并明确需要使用的 Broadcast action ,如果需要处理系统的广播,则直接通过 android.intent.action.XXX 引用就可以了,如果自定义广播,则需要定义 Action 。如下代码所示:

public class BRDemo extends BroadcastReceiver {

    public static String YOUR_CUSTOM_BROADCAST_ACTION_NAME = “ANY_NAME_HERE”;

   /* 必须重载 onReceive 方法 */

    @Override

    public void onReceive(Context context, Intent intent) {

       //todo: 在这里添加处理的代码

     …………..

    }

}

                  其次,注册 Broadcast Receiver 。前面提到过, Android 提供了两种注册广播接受者的形式,分别是动态注册和在 xml 中静态注册。他们之间的区别就是作用的范围不同,程序动态注册的接收者只在程序运行过程中有效,而在 xml 注册的接收者不管你的程序有没有启动有会起作用。

A.     动态注册方式。

动态注册的方式。

// 注册广播   

registerReceiver(instance, intentFilter);   

//Note: onDestroy 要注销广播   

调用 unregisterReceiver(..) 函数 ;   

 

B.      静态注册方式。

 

<?xml version="1.0" encoding="utf-8"? <?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android "
      package="YOUR_PACKAGE_NAME"
      android:versionCode="1"
      android:versionName="1.0">
    <application android:icon="@drawable/icon" android:label="@string/app_name">
        <activity android:name="YOUR_ACTIVITY "
                  android:label="@string/app_name">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    <receiver android:name="BroadcastRecTest">
        <intent-filter>

// 定义 Receiver Action
            <action android:name=" YOUR_CUSTOM_BROADCAST_ACTION_NAME" />
             </intent-filter>
    </receiver>

    </application>

</manifest>

最后,可以发送广播了。

// 生成广播处理   

YOUR_BROADCAST_RECEIVER_CLASS instance= new YOUR_BROADCAST_RECEIVER_CLASS();   

// 实例化过滤器并设置要过滤的广播      

IntentFilter intentFilter = new IntentFilter(YOUR_CUSTOM_BROADCAST_ACTION_NAME);   

4.4  应用实例详解

                  以上我们详细讨论 Android intent broadcast ,也说明了它们的使用方式,接下来我们将通过一个实例,讲解 intent broadcast 的使用。

1.     新建一个 Android 项目,这个项目使用 Intent 发送一个自定义 Broadcast 。如图 4-8

4-8 Android demo

 

2.     定义 Broadcast Action name 。如图 4-9

4-9 定义广播 Action

 

3.     新建一个 class, 继承 BroadcastReceiver, 这个方式实现,是处理静态的广播如图 4-10 ,处理动态广播的 class 如图 4-12

4-10 新建广播接收器

4.     注册 BroadcastReceiver, 静态注册如图 4-11 ,动态注册如图 4-12

4-11 静态注册

4-12 动态注册

5.     发送广播。如图 4-13

4-13 发送广播

以上基本完成了利用 Intent 发送广播的例子,其中涵盖了静态和动态注册两种方式,源代码可以参考 /demo/source/demo_044

Android 上我们可以完成很多神奇的应用,下面列举常用的一些例子:

显示网页:
     Uri uri = Uri.parse(URL_YOU_WANT_TO_BROWSE);
     Intent it = new Intent(Intent.ACTION_VIEW,uri);
     startActivity(it);

显示 google 地图 :
     Uri uri = Uri.parse("geo:XXX,XXX");
     Intent it = new Intent(Intent.Action_VIEW,uri);
     startActivity(it);

Maps
路径规划 :
     Uri uri= Uri.parse("YOUR_URL_HERE");

     Intent it = new Intent(Intent.ACTION_VIEW,URI);
     startActivity(it);

拨打电话 :
     Uri uri = Uri.parse("tel:xxxxxx");
     Intent it = new Intent(Intent.ACTION_DIAL, uri); 
     startActivity(it); 

     Note: <uses-permission id="Android.permission.CALL_PHONE" />

发送 SMS/MMS:
     Intent it = new Intent(Intent.ACTION_VIEW);
     it.putExtra("sms_body", "android
开发网欢迎您 ");
     it.setType("vnd.android-dir/mms-sms");
     startActivity(it); 


发送短信 :
     Uri uri = Uri.parse("smsto:10086");
     Intent it = new Intent(Intent.ACTION_SENDTO, uri);
     it.putExtra("sms_body", "10086"); //
正文为 10086
     startActivity(it); 


发送彩信 :
     Uri uri = Uri.parse("YOUR_CONTENT_PATH"); //
Uri 根据实际情况修改, external 代表外部存储即 sdcard
     Intent it = new Intent(Intent.ACTION_SEND);
     it.putExtra("sms_body", "android123.com.cn");
     it.putExtra(Intent.EXTRA_STREAM, uri);
     it.setType("image/png");
     startActivity(it);
发送 Email:

     Uri uri = Uri.parse("mailto:MAIL_ADDRESS");//URI 指定邮箱地址实现
     Intent it = new Intent(Intent.ACTION_SENDTO, uri);
     startActivity(it);

     Intent it = new Intent(Intent.ACTION_SEND);//
通过 Intent 实现
     it.putExtra(Intent.EXTRA_EMAIL, "YOUR_MAIL_ADDRESS");
     it.putExtra(Intent.EXTRA_TEXT, "MESSAGE_BODY");
     it.setType("text/plain");
     startActivity(Intent.createChooser(it, "
选择一个邮件发送客户端 ")); 

     Intent it=new Intent(Intent.ACTION_SEND);  );//
通过 Intent 实现,数据放在外部,添加抄送
     String[] tos={"SUBJECT_MAIL_ADDRESS"};     //
发送到
     String[] ccs={"CC_MAIL_ADDRESS"};    //
抄送
     it.putExtra(Intent.EXTRA_EMAIL, tos); 
     it.putExtra(Intent.EXTRA_CC, ccs); 
     it.putExtra(Intent.EXTRA_TEXT, "
正文 "); 
     it.putExtra(Intent.EXTRA_SUBJECT, "
标题 "); 
     it.setType("message/rfc822");    //
编码类型
     startActivity(Intent.createChooser(it, "
选择一个邮件客户端 "));

Email 添加附件:
     Intent it = new Intent(Intent.ACTION_SEND);
     it.putExtra(Intent.EXTRA_SUBJECT, "
正文 ");
     it.putExtra(Intent.EXTRA_STREAM, "ATTACHMENT_FILE_PATH"); //
附件的路径
     sendIntent.setType("RESOURCE_TYPE");
     startActivity(Intent.createChooser(it, "
选择一个 Email 客户端 "));

播放多媒体 :
     Intent it = new Intent(Intent.ACTION_VIEW);
     Uri uri = Uri.parse("FILE_PATH");
     it.setDataAndType(uri, "FILE_TYPE");
     startActivity(it);

 

分享到:
评论

相关推荐

    Android Intent Service BroadCast AndroidStudio

    Intent_broadcast主要是静态广播的注册;Intent_broadcastdynamic主要介绍动态广播的注册;intent_service主要是启动服务来播放音乐(我今年正好十八岁-阿正)。 本项目使用Android Studio 1.4 编写。

    Google.Android开发入门与实战

    Google.Android开发入门与实战_第9章_我来“广播”你的“意图”——Intent和Broadcast面对面

    《Google Android开发入门与实战》

    第9章 我来“广播”你的“意图”——Intent和Broadcast面对面 第10章 一切为用户服务——Service应用实例 第12章 Android综合案例一——RSS阅读器实例 第14章 Android综合案例三——基于Android的豆瓣网(Web2.0)移动...

    android开发入门教程

    第9章 我来“广播”你的“意图”——Intent和Broadcast面对面 9.1 Android应用程序的核心——Intent 9.1.1 Intent基础 9.1.2 用Intent启动一个新的Activity 9.1.3 Intent详细讲解 9.1.4 Android解析Intent实现 9.2 ...

    android开发入门与实战(下)

    第9章 我来“广播”你的“意图”——Intent和Broadcast面对面 9.1 Android应用程序的核心——Intent 9.1.1 Intent基础 9.1.2 用Intent启动一个新的Activity 9.1.3 Intent详细讲解 9.1.4 Android解析Intent实现 9.2 ...

    android开发入门与实战(上)

    第9章 我来“广播”你的“意图”——Intent和Broadcast面对面 9.1 Android应用程序的核心——Intent 9.1.1 Intent基础 9.1.2 用Intent启动一个新的Activity 9.1.3 Intent详细讲解 9.1.4 Android解析Intent实现 9.2 ...

    《Google Android开发入门与实战》.pdf

    第9章 我来“广播”你的“意图”——intent和broadcast面对面 174 9.1 android应用程序的核心——intent 174 9.1.1 intent基础 174 9.1.2 用intent启动一个新的activity 174 9.1.3 intent 详细讲解 ...

    Google Android开发入门与实战的代码

    第9章 我来“广播”你的“意图”——Intent和Broadcast面对面 174 9.1 Android应用程序的核心——Intent 174 9.1.1 Intent基础 174 9.1.2 用Intent启动一个新的Activity 174 9.1.3 Intent 详细讲解 ...

    Android中关于Broadcast、Intent 的应用

    Android中关于Broadcast、Intent 的应用,对于初学Android者有较大帮助。

    Android Intent和Intent Filter详解

     三种应用程序基本组件——activity, service和broadcast receiver——是使用称为intent的消息来激活的。Intent消息传递是一种组件间运行时绑定的机制. intent是Intent对象, 它包含了需要做的操作的描述, 或者, ...

    Intent_Broadcast_Practice6.rar

    设计三个界面,前两个界面单击下一步按钮后,启动到下一个界面,并且把界面上的信息传递给下一个界面, 在第三个界面上显示前两个界面所填写内容,单击确认并提交按钮后发送一个广播,广播接收器接收到一个将信息...

    android Intent的用法

    详细介绍android 的用法

    android之旅-Intent和BroadcastReceiver示例代码

    Intent和BroadcastReceiver示例代码

    Android 学习(26)Intent 分类

    自学 Android 做的第二十六个 Android 程序,使用了 Intent 和 Broadcast Receiver

    Intent和PendingIntent的区别

    简单的总结了Intent和PendtingIntent的区别,经常与alermanger 和notificationmanager一起使用。

    Intent用法举例

    举例说明了intent用于broadcast以及service的一些方法

    Android利用Intent启动和关闭Activity

    主要为大家详细介绍了Android利用Intent启动和关闭Activity的相关操作,感兴趣的小伙伴们可以参考一下

    Android Intent传递数据大小限制详解

    在sendBroadcast,startActivity时,我们会用到Intent。 Intent可以携带一些数据,比如基本类型数据int、Boolean,或是String,或是序列化对象,Parcelable与Serializable。 Intent传递数据时,如果数据太大,可能...

    Android使用Intent和Intentfilter进行通信

    Android使用Intent和Intentfilter进行通信,源于《疯狂Android讲义》值得学习

Global site tag (gtag.js) - Google Analytics