BroadcastReceiver

本文介绍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 {//如果接收的事件发生
    @Overridepublic 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. */@Overridepublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.main);Button b1 = (Button) findViewById(R.id.Button01);b1.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {//定义一个intentIntent 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 {//如果接收的事件发生
    @Overridepublic 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 ;@Overridepublic void onReceive(Context context, Intent intent) {// TODO Auto-generated method stubString 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结合使用以确保执行这个操作的进程在整个执行过程中都保持激活状态。

转载于:https://www.cnblogs.com/maydow/p/5082763.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/458509.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

如何确定VS编译器版本--_MSC_VER || #if _MSC_VER 1000 #pragma once #endif

如何确定VS编译器版本 _MSC_VER是MSVC编译器的内置宏&#xff0c;定义了编译器的版本&#xff0c;_MSC_VER 值对应版本关系 MSVC 11.0 _MSC_VER 1700 (Visual Studio 2012) MSVC 10.0 _MSC_VER 1600 (Visual Studio 2010) MSVC 9.0 _MSC_VER 1500 (Visual Studio 2008) …

NIO复习02

Selector 1. Selector&#xff08;选择器&#xff09;是Java NIO中能够检测一到多个NIO通道&#xff0c;并能够知晓通道是否为诸如读写事件做好准备的组件。这样&#xff0c;一个单独的线程可以管理多个channel&#xff0c;从而管理多个网络连接。 2. Selector的创建&#xff1…

c/c++标准预定义宏

C标准中的一些预定义宏昨天写代码时需要在代码获取当前编译时间&#xff0c;从而可动态地作为版本信息&#xff0c;因此用到了C标准中的一些预定义的宏。在此将C标准中定义的几个宏一并总结一下&#xff1a; __DATE__ 进行预处理的日期&#xff08;“Mmm dd yyyy”形式的字符串…

安装cocoa pods时出现Operation not permitted - /usr/bin/xcodeproj的问题

在更新完ruby&#xff0c;更换Ruby镜像&#xff0d;&#xff0d;淘宝的那个镜像(https://ruby.taobao.org/ )已经不可用了。官方的需要FQ。所以我们现在用最新支持的ruby镜像(https://gems.ruby-china.org/) 安装cocoa pods时&#xff0c; 在命令行中输入&#xff1a; 安装&…

js 日期控件laydate使用

官网 http://sentsin.com/layui/laydate/ 1. 下载官网上的压缩包,解压后只需要复制laydate 文件夹到你的项目中; 2. 在页面引入 <script type"text/javascript" src"js/laydate/laydate.js"></script> 3. 在页面添加: <div class"i…

老李推荐:第8章2节《MonkeyRunner源码剖析》MonkeyRunner启动运行过程-解析处理命令行参数 2...

我们这一节会先去分析下monkeyrunner是如何对参数进行处理的&#xff0c;我们跳转到MonkeyRunnerOptions这个类里面的processOptions这个方法&#xff1a; 93 public static MonkeyRunnerOptions processOptions(String[] args) 94 { 95 int index 0; 96 97 Strin…

MFC CPropertySheet 多页面切换 实例

为了能实现在同一个页面实现多个页面的切换效果。CPropertySheet要与CPropertyPage一起使用。 首先 新建一个MFC工程--MFC AppWizard(exe), 取名Pagesheet, 选择Dialog based, 然后Finish. 2. 在对话框资源中插入两个对话框IDD_DIALOG1、IDD_DIALOG2&#xff0c;作为…

ReactiveCocoa简单介绍

ReactiveCocoa 的简单介绍 http://www.jianshu.com/p/87ef6720a096

游戏提高性能 游戏降帧处理

什么是降帧&为什么降帧 一般情况下我们为了提高整个游戏的体验&#xff0c;所以我们一般会将游戏的帧数&#xff08;每秒钟刷新多少次&#xff09;设置的比较高。一般情况下&#xff0c;我们的游戏所有的代码都是一帧执行一次。为了让每一帧都变成真的关键数据帧。不过&…

delphi 更改DBGrid 颜色技巧

1、根据条件更改某一单元格的颜色 [delphi] view plaincopy procedure TMainFrm.First_DGDrawColumnCell(Sender: TObject; const Rect: TRect; DataCol: Integer; Column: TColumn; State: TGridDrawState); begin if DM.FirstListStatus.AsString生产 then begin …

mfc中UpdateData的用法

http://blog.csdn.net/ddjj_1980/article/details/51452289 UpdateData(TRUE)——刷新控件的值到对应的变量。(外部输入值交给内部变量)即&#xff1a;控件的值—>变量。UpdateData(FALSE)—— 拷贝变量值到控件显示。(变量的最终运算结果值交给外部输出显示)即&#xff1a;…

动画类的层次结构

CASpringAnimation类是CAABasicAnimation的子类 CAPropertyAnimation &#xff1a;是CAAnimation的子类&#xff0c;它支持动画地显示图层的keyPath&#xff0c;一般不直接使用。 iOS9.0之后新增CASpringAnimation类&#xff0c;它实现弹簧效果的动画&#xff0c;是CABasicAnim…

[原]小命令大作用:modprobe

调整网络为绑定模式&#xff0c;但启动时候会报错&#xff0c;此时执行命令 modprobe bonding 可以解决问题。 之前在磁盘方面遇到问题也是通过modprobe命令解决的&#xff0c;又遇到这个命令&#xff0c;似曾相识。于是看下该命令&#xff1a; Linux命令&#xff1a;modprobe …

sql语句优化之not in

多表关联想查a表中除去b表的可用not exists 效率比not in 更高 优化后的语句用时0.421秒 select john.*, (case when round((case john.sumcount when 0 then 0 else mycount * 100 / sumcount end), 2) > 100 then 100 else round((case john.sumcount when 0 then 0 else …

setup2go制作安装程序

QT程序设计完毕时&#xff0c;我们就要发布自己的程序&#xff0c;发布程序有两种方法&#xff1a;一是静态编译&#xff0c;二是制作程序安装包。 静态编译好麻烦&#xff0c;我从来没有成功过&#xff0c;所以我用了动态编译方法&#xff0c;设计完成时&#xff0c;用release…

gson-2.2.api简单

使用gson的tojson和fromjson实现对象和json的转换 Gson gson new Gson(); // Or use new GsonBuilder().create(); MyType target new MyType(); String json gson.toJson(target); // serializes target to Json MyType target2 gson.fromJson(json, MyType.c…

用户需求、己、竞争对手的关系

图一 图二 图三 如第一图所示&#xff1a;现在在市面上的产品基本上都可以归纳为这一方面&#xff0c; 如“用户需求”是网上购物的需求&#xff0c;以“己”是京东为例子&#xff0c;“己”的…

SharePoint 入门介绍

from&#xff1a;http://www.cnblogs.com/jianyus/archive/2013/01/11/2856963.html 前言&#xff1a;接触SharePoint两年有余&#xff0c;从一开始的小白&#xff0c;变成现在的菜鸟&#xff0c;一路走来&#xff0c;学到很多&#xff0c;现在&#xff0c;想把自己知道的东西&…

AJAX-服务器响应

服务器响应 如需获得来自服务器的响应&#xff0c;请使用 XMLHttpRequest 对象的 responseText 或 responseXML 属性。 属性 描述 responseText 获得字符串形式的响应数据。 responseXML 获得 XML 形式的响应数据。 responseText 属性 如果来自服务器的响应并非 XML&#xff0c…

c#下不同命名空间的引用(一个project使用另外一个project的名称空间)

http://bbs.csdn.net/topics/300089064 两个命名空间在同一个项目中时&#xff0c;没有任何问题。 若两个命名空间不在同一个项目中&#xff0c;则变成两个程序集之间的互相引用。 程序集之间的引用无所谓循环不循环的问题。 但如果两个程序集要互相引用&#xff0c;并且两个…