android 四大组件Broadcast Receiver
本文介绍Broadcast Receiver,包括几部分内容:Broadcast Receiver概述及实例、自定义Broadcast Receiver、Broadcast Receiver的实现细节、生命周期等。
csdn貌似今天出问题了,无法上传图片。
资料来源:最牛网,《官方解读BroadcastReceiver》《Android中Broadcast Receiver组件详解》《(转)第二十一讲:Broadcast Receiver 使用入门》
BroadcastReceiver(广播接收器)是Android中的四大组件之一。
下面是Android Doc中关于BroadcastReceiver的概述:
①广播接收器是一个专注于接收广播通知信息,并做出对应处理的组件。很多广播是源自于系统代码的──比如,通知时区改变、电池电量低、拍摄了一张照片
或者用户改变了语言选项。应用程序也可以进行广播──比如说,通知其它应用程序一些数据下载完成并处于可用状态。
②应用程序可以拥有任意数量的广播接收器以对所有它感兴趣的通知信息予以响应。所有的接收器均继承自BroadcastReceiver基类。
③广播接收器没有用户界面。然而,它们可以启动一个activity来响应它们收到的信息,或者用NotificationManager来通知用
户。通知可以用很多种方式来吸引用户的注意力──闪动背灯、震动、播放声音等等。一般来说是在状态栏上放一个持久的图标,用户可以打开它并获取消息。
Android中的广播事件有两种,一种就是系统广播事件,比如:ACTION_BOOT_COMPLETED(系统启动完成后触
发),ACTION_TIME_CHANGED(系统时间改变时触发),ACTION_BATTERY_LOW(电量低时触发)等等。另外一种是我们自定
义的广播事件。
广播事件的流程
①注册广播事件:注册方式有两种,一种是静态注册,就是在AndroidManifest.xml文件中定义,注册的广播接收器必须要继承
BroadcastReceiver;另一种是动态注册,是在程序中使用Context.registerReceiver注册,注册的广播接收器相当于
一个匿名类。两种方式都需要IntentFIlter。
②发送广播事件:通过Context.sendBroadcast来发送,由Intent来传递注册时用到的Action。
③接收广播事件:当发送的广播被接收器监听到后,会调用它的onReceive()方法,并将包含消息的Intent对象传给它。onReceive中代码的执行时间不要超过5s,否则Android会弹出超时dialog。
Broadcast Receiver接收系统自带的广播
我们做一个例子,功能是在系统启动时播放一首音乐。
1、建立一个项目Lesson21_BroadcastReceiver,拷贝一首音乐进res/raw目录
2、建立HelloBroadcastReceiver.java 内容如下:
- Codepackage android.basic.lesson21;
- import android.content.BroadcastReceiver;
- import android.content.Context;
- import android.content.Intent;
- import android.media.MediaPlayer;
- import android.util.Log;
- public class HelloBroadReciever extends BroadcastReceiver {
- //如果接收的事件发生
- @Override
- public void onReceive(Context context, Intent intent) {
- //则输出日志
- Log.e("HelloBroadReciever", "BOOT_COMPLETED!!!!!!!!!!!!!!!!!!!!!!!!!");
- Log.e("HelloBroadReciever", ""+intent.getAction());
- //则播放一首音乐
- MediaPlayer.create(context, R.raw.babayetu).start();
- }
- }
3、在AndroidManifest.xml中注册此Receiver :
- Code<?xml version="1.0" encoding="utf-8"?>
- <manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionname="1.0" android:versioncode="1" package="android.basic.lesson21">
- <application android:icon="@drawable/icon" android:label="@string/app_name">
- <activity android:label="@string/app_name" android:name=".MainBroadcastReceiver">
- <intent -filter="">
- <action android:name="android.intent.action.MAIN">
- <category android:name="android.intent.category.LAUNCHER">
- </category></action></intent>
- </activity>
- <!-- 定义Broadcast Receiver 指定监听的Action -->
- <receiver android:name="HelloBroadReciever">
- <intent -filter="">
- <action android:name="android.intent.action.BOOT_COMPLETED">
- </action></intent>
- </receiver>
- </application></manifest>
4、发布程序,启动模拟器,可以在Logcat中看到:

同时能听到音乐播放的声音。说明我们确实接收到了系统启动的广播事件,并做出了响应。

三、自定义广播
下面我们学习自己制作一个广播。我们接着刚才的例子,继续写下去。
5、在MainBroadcastReceiver.java中填写如下代码:
- Codepackage android.basic.lesson21;
- import android.app.Activity;
- import android.content.Intent;
- import android.os.Bundle;
- import android.view.View;
- import android.widget.Button;
- public class MainBroadcastReceiver extends Activity {
- /** Called when the activity is first created. */
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.main);
- Button b1 = (Button) findViewById(R.id.Button01);
- b1.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- //定义一个intent
- Intent intent = new Intent().setAction(
- "android.basic.lesson21.Hello").putExtra("yaoyao",
- "yaoyao is 189 days old ,27 weeks -- 2010-08-10");
- //广播出去
- sendBroadcast(intent);
- }
- });
- }
- }
6、更改 HelloBroadReceiver.java 内容如下:
- Codepackage android.basic.lesson21;
- import android.content.BroadcastReceiver;
- import android.content.Context;
- import android.content.Intent;
- import android.media.MediaPlayer;
- import android.util.Log;
- public class HelloBroadReciever extends BroadcastReceiver {
- //如果接收的事件发生
- @Override
- public void onReceive(Context context, Intent intent) {
- //对比Action决定输出什么信息
- if(intent.getAction().equals("android.intent.action.BOOT_COMPLETED")){
- Log.e("HelloBroadReciever", "BOOT_COMPLETED !!!!!!!!!!!!!!!!!!!!!!!!!");
- }
- if(intent.getAction().equals("android.basic.lesson21.Hello")){
- Log.e("HelloBroadReciever", "Say Hello to Yaoyao !!!!!!!!!!!!!!!!!!!!!!!!!");
- Log.e("HelloBroadReciever", intent.getStringExtra("yaoyao"));
- }
- //播放一首音乐
- MediaPlayer.create(context, R.raw.babayetu).start();
- }
- }
7、更改 AndroidManifest.xml 内容如下:
- <?xml version="1.0" encoding="utf-8"?>
- <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="android.basic.lesson21" android:versionname="1.0" android:versioncode="1">
- <application android:icon="@drawable/icon" android:label="@string/app_name">
- <activity android:label="@string/app_name" android:name=".MainBroadcastReceiver">
- <intent -filter="">
- <action android:name="android.intent.action.MAIN">
- <category android:name="android.intent.category.LAUNCHER">
- </category></action></intent>
- </activity>
- <!-- 定义Broadcast Receiver 指定监听的Action 这里我们的接收器,接收了2个Action,一个系统的一个我们自定义的 -->
- <receiver android:name="HelloBroadReciever">
- <intent -filter="">
- <action android:name="android.intent.action.BOOT_COMPLETED">
- </action></intent>
- <intent -filter="">
- <action android:name="android.basic.lesson21.HelloYaoYao">
- </action></intent>
- </receiver>
- </application>
- <uses -sdk="" android:minsdkversion="8">
- </uses></manifest>
8、运行程序,点击按钮,查看LogCat,听听声音


在使用Broadcast
时我们应该注意到,BroadcastReceiver的子类别都是无状态的类别,每次收到发送广播事件后,BroadcastReceiver都会创建
一个新的对象,然后再执行onReceive()函数,当onReceive()函数执行完毕后,就立刻删掉该对象,下一次再收到此广播后,又会创建一个
新的对象。所以说Broadcast组建是Android中最轻薄、最短小的组建。我们增加了一个static的变量numStatic ,和num变量
。代码如下:
- /**
- * Broadcaster.java
- * com.androidtest.broadcaster
- *
- * Function: TODO
- *
- * ver date author
- * ──────────────────────────────────
- * 2011-6-9 Leon
- *
- * Copyright (c) 2011, TNT All Rights Reserved.
- */
- package com.androidtest.broadcaster;
- import android.content.BroadcastReceiver;
- import android.content.Context;
- import android.content.Intent;
- import android.util.Log;
- /**
- * ClassName:Broadcaster
- * Function: TODO ADD FUNCTION
- * Reason: TODO ADD REASON
- *
- * @author Leon
- * @version
- * @since Ver 1.1
- * @Date 2011-6-9
- */
- public class Broadcaster extends BroadcastReceiver{
- private static final String TAG = "Broadcaster";
- private static int numStatic =100 ;
- private int num =100 ;
- @Override
- public void onReceive(Context context, Intent intent) {
- // TODO Auto-generated method stub
- String string = intent.getAction();
- numStatic= numStatic+50;
- num=100+50;
- Log.v(TAG , "The action is "+ string + "Static Number is :" + numStatic
- + " Object num is :" + num);
- }
- }
多次发送广播,然后输出的结果如下,我们可以看到static Number 每次执行都会增加,而Object Num因为每次都要创建所以一直都是一个固定的值。

上文中提到了BroadcastReceiver是Android中最轻薄、最短小的组件,它的对象生命周期十分短暂,经过傻蛋测试在
BroadcastReceiver中让线程睡眠10秒(Activity是5秒钟)的话,Android就会弹出错误(和Activity超时的错误相
同),同时需要注意的是Activity、Service和BroadcastReceiver都是运行在本进程的主线程里面的。通过这个测试让傻蛋进一
步产生了疑问,如果在Service中处理一个长时间的任务会怎么样?
启动一个Service,然后在Service的onCreate()方法中添加如下代码:
- try {
- Log.v(TAG , "sleep start …..");
- Thread.sleep(20000);
- Log.v(TAG,"sleep end …..");
- } catch (InterruptedException e) {
- / / TODO Auto-generated catch block
- e.printStackTrace();
- }
很简单就是让Service睡眠20秒钟,我们会发现,sleep start…. 和 sleep end….这两个日志打印出来了,但是后台还会出现如下错误,前台弹出no response超时对话框。

在onCreate()中新启动一个线程来,睡眠时,程序正常。
所以总结一下:无论是 Activity、BroadcastReceiver还是Service,只要是有长时间处理的任务,就需要重新开一个线程来处理,为什么会这样?因为他们都是运行在主线程中的。
在使用BroadcastReceiver时还有一个我们需要注意的:在BroadcastReceiver的onReceive(Context
context , Intent intent
)这第一个context到底是哪一个context?是Activity还是Application?通过测试发现:
如果你的BroadcastReceiver是通过在Activity中的this.registerReceiver(myBroadcaster,
filter);
来注册的话,那么这个context就是这个Activity,而如果是通过AndroidManifest来注册的话,那么这个context就
是:android.app.ReceiverRestrictedContext。
BroadcastReceiver是接收从sendBroadcast()发出的intent的基类。你可以通过
Context.registerReceiver()方法在代码中动态的注册一个BroadcastReceiver的实例,也可以通过再
AndroidManifest.xml文件中用<receiver>标签来静态声明。
注意:如果你实在Activity.onResume()方法中注册的一个receiver,那么你必须在Activity.onPause()方法中
进行注销。(当一个activity处于暂停状态是不会接收intents的,并且这样做也可以减小系统不必要的开销)。不要在
Activity.onSaveInstanceState()方法中注销receiver,因为activity从栈中恢复的时候并不会调用这个方法
了。
可以接收的broadcast主要分为两种类型:
普通的broadcasts(通过Context.sendBroadcast发送)是完全异步的。这个broadcast的receiver以无序的状
态运行,经常是在同一时刻运行。这种做法是十分高效的,但是也意味着receiver不能够利用相互处理的结果或者是调用退出的API来退出(因为不知道
哪个receiver先接收到intent)。
有序的broadcasts(通过Context.sendOrderedBroadcast发送)一次只发送给一个receiver。每一个
receiver是有序的处理这个intent的,前面的receiver可以传递结果给下一个receiver,或者任意一个receiver都可以完
全的退出,这样intent就不会传递给其他的receivers.receiver的执行顺序可以通过匹配的intent-filter中的
android:priority属性来控制;如果有多个receivers处于同一个优先级,那么这几个receivers将会以任意的顺序来执行。
即使是在广播普通的broadcasts的情况下,系统也有可能在某些情况下转换为一次发送一个broadcast给一个receriver。特别是当
receivers需要创建进程时,在同一时刻仅仅一个receiver可以运行,避免系统因为这些新建的进程而过载。
注意:尽管Intent类是用来发送和接受这些broadcasts,这里的Intent
broadcast机制和那些通过Context.startActivity()方法来启动activity的intent是完全独立的。一个
BroadcastReceiver是没办法观察和捕获一个用于启动activity的intent的;同样的,当你通过intent来发出
broadcast时,你也不可能(通过这个intent)找到或者启动一个activity的。这两种操作是完全不同的:通过一个intent来启动一
个activity是一个前台操作,会改变用户当前交互的对象;而通过intent来发出broadcast是一个后台操作,用户经常是察觉不到的。
BroadcastReceiver类(通过一个manifest的<receiver>标签作为一个组件启动)是应用程序全局声明周期重要的一部分。
讨论的主题
1、Receiver的生命周期
2、权限
3、进程的生命周期
开发者指南
更详细的关于如何获取和解析一个Intent的内容,请详见Intents and Intent Filters开发者指南
Receiver的生命周期
一个BroadcastReceiver的对象仅仅在调用onReceiver(COntext, Intent)的时间中有效。一旦你的代码从这个函数中返回,那么系统就认为这个对象应该结束了,不能再被激活。
你在onReceive(Context,
Intent)中的实现有着非常重要的影响:任何对于异步操作的请求都是不允许的,因为你可能需要从这个函数中返回去处理异步的操作,但是在那种情况
下,BroadcastReceiver将不会再被激活,因此系统就会再异步操作之前杀死这个进程。
特别是,你不应该再一个BroadcastReceiver中显示一个对话框或者绑定一个服务。对于前者(显示一个对话框),你应该用
NotificationManagerAPI来替代,对于后者(绑定一个服务),你可以使用Context.startService()发送一个命令
给那个服务来实现绑定效果。
权限
存取的权限可以通过在发送方的Intent或者接收方的Intent中强制指定。
在发送一个broadcast时强制指定权限,就必须提供一个非空的peemission参数给sendBroadcast(Intent,
String)或者是sendOrderedBroadcast(Intent, String, BroadcastReceiver,
android.os.Handel, int, String,
Bundle).只有那些拥有这些权限(通过在ANdroidManifest.xml文件中相应的声明<uses-permission>
标签)的receiver能够接收这些broadcast。
在接收一个broadcast时强制指定权限,就必须在注册receiver时提供一个非空的permission参数--无论是在调用
registerReceiver(BroadcastReceiver, IntentFilter, String,
android.os.Handler)或者是通过再AndroidManifest.xml文件中通过<receiver>静态标签来声
明。只有那些拥有这些权限(通过在相应的AndroidManifest.xml文件中查询<uses-permission>标签来获知)
的发送方将能够给这个receiver发送Intent。
对于安全和权限的详细内容请查看Security and Permission文档。
进程的生命周期
一个正在执行BroadcastReceiver(也就是,正在执行onReceive(COntext, Intent)方法)的进程被认为是一个前台的进程,将会一直运行,除非系统处于内存极度低的情况下。
一旦从OnReceive()方法中返回,这个BroadcastReceiver将不会再被激活,此时它的主进程就和任何其他运行于此应用程序中的组件
拥有相同的优先级。这一点非常重要,如果进程仅仅只是拥有BroadReceiver(一个普遍的情况是用户从不或者是最近没有和它进行交互),因此一旦
它从onReceive()方法中返回时,系统就会认为进程是空的并且主动的杀死它,以便这些资源可以被其他重要的进程利用。
这意味着对于耗时的操作,可以采用将Service和BroadcastReceiver结合使用以确保执行这个操作的进程在整个执行过程中都保持激活状态。
android 四大组件Broadcast Receiver的更多相关文章
- Android四大组件--Broadcast Receiver具体解释
本文主要讲述了: 一.BroadcastReceiver概述: 二.BroadcastReceiver事件分类 三.BroadcastReceiver事件的编程流程 四.两类BroadcastRece ...
- Android四大组件-Broadcast Receiver
http://www.jianshu.com/p/1013a366cc72 http://www.jianshu.com/p/ca3d87a4cdf3 前言 基础知识. 1.Android广播分为两个 ...
- android四大组件--ContentProvider具体解释
一.相关ContentProvider概念解析: 1.ContentProvider简单介绍 在Android官方指出的Android的数据存储方式总共同拥有五种,各自是:Shared Prefere ...
- 【转】android四大组件--ContentProvider详解
一.相关ContentProvider概念解析: 1.ContentProvider简介在Android官方指出的Android的数据存储方式总共有五种,分别是:Shared Preferences. ...
- 【Android开发日记】之入门篇(六)——Android四大组件之Broadcast Receiver
广播接受者是作为系统的监听者存在着的,它可以监听系统或系统中其他应用发生的事件来做出响应.如设备开机时,应用要检查数据的变化状况,此时就可以通过广播来把消息通知给用户.又如网络状态改变时,电量变化时都 ...
- android四大组件之Broadcast
广播的概念 现实中:我们常常使用电台通过发送广播发布消息,买个收音机,就能收听 Android:系统在产生某个事件时发送广播,应用程序使用广播接收者接收这个广播,就知道系统产生了什么事件.Androi ...
- Android 四大组件之service与Broadcast
Android 四大组件之一:service: Service有五个生命周期:onCreat,onStartCommand, onBind,onUnbind, onDestroy 主要有绑定和非绑定两 ...
- [Android基础]Android四大组件之BroadCast
BroadCast的定义: 广播是一种订阅--通知 事件,广播接收者向Android系统 register (订阅广播),广播发送者向Adnroid系统 sendBroadCast(发送广播),然后A ...
- Android四大组件之一“广播”
前言 Android四大组件重要性已经不言而喻了,今天谈谈的是Android中的广播机制.在我们上学的时候,每个班级的教室里都会装有一个喇叭,这些喇叭都是接入到学校的广播室的,一旦有什么重要的通知,就 ...
随机推荐
- C++ 的全局构造与析构函数
我们知道一般的C/C++ 的程序是从main函数开始的,然后在main函数结束后程序结束.但是不然,在main函数开始执行前,已经有其他的指令被执行了. 为了程序的顺利执行,首先要初始化执行环境,比如 ...
- Android:ViewPager实现屏幕轮转和使用PagerTabStrip
① ViewPager类直接继承了ViewGroup类,所有它是一个容器类,可以在其中添加其他的view类. ② ViewPager类需要一个PagerAdapter适配器类给它提供数据. ③ Vie ...
- 管理员必备的20个Linux系统监控工具
需要监控Linux服务器系统性能吗?尝试下面这些系统内置或附件的工具吧.大多数Linux发行版本都装备了大量的监控工具.这些工具提供了能用作取得相关信息和系统活动的量度指标.你能使用这些工具发现造成性 ...
- OSGi之Bundle
OSGi提出的根源是什么?在我看来就是对JVM的类加载机制进行了扩展,添加了一系列的规则,使得原有的类包(Class Package)扩展到类域(Class Domain).然后是建立在类域上的一系列 ...
- 跨域访问-需要设置HTTP响应标头设置
跨域访问-需要设置HTTP响应标头设置 前提:服务端网站的配置(被请求的网站) 1.需要在IIS服务器站点的功能视图中设置HTTP响应标头: 2.双击“HTTP响应标头”进入设置界面 3.点击右侧添加 ...
- Java中的访问权限
Java中有四种访问权限,从大到小依次是:public –> protected –> default(friendly) –> private. 简单说明下: public 作用域 ...
- Json.Net使用JSON Schema验证JSON格式【实例】
给出一个Json,验证其格式是否符合规则. { "coord": { //对象 "lon": 145.77, "lat": -16.92 } ...
- iOS10推送必看UNNotificationServiceExtension
转:http://www.cocoachina.com/ios/20161017/17769.html (收录供个人学习用) iOS10推送UNNotificationServic 招聘信息: 产品经 ...
- 使用Java 8 API,根据传递的分隔符,连接list中所有的元素
public class MethodReferenceDemo1 { @FunctionalInterface interface StringListFormatter { String form ...
- 【转载】《Ext JS 4 First Look》翻译之一:新特性
免责声明: 本文转自网络文章,转载此文章仅为个人收藏,分享知识,如有侵权,请联系博主进行删除. 原文作者:^_^肥仔John 原文地址:http://www.cnblogs. ...