Android四大组件Broadcast Receiver详解

2024-04-29 01:48

本文主要是介绍Android四大组件Broadcast Receiver详解,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

文章来源:http://www.itnose.net/detail/6030479.html

更多文章:http://www.itnose.net/type/85.html

本文主要讲述了:

一、BroadcastReceiver概述:

二、BroadcastReceiver事件分类

三、BroadcastReceiver事件的编程流程

四、两类BroadcastReceiver

五、普通广播和有序广播

六、Service与BroadcastReceiver如何交互?

七、开机自动运行service

八、BroadcastReceiver的生命周期

 

一、BroadcastReceiver概述:

1、广播接收器是一个专注于接收广播通知信息,并做出对应处理的组件。很多广播是源自于系统代码的──比如,通知时区改变、电池电量低、拍摄了一张照片或者用户改变了语言选项。应用程序也可以进行广播──比如说,通知其它应用程序一些数据下载完成并处于可用状态。 
2、应用程序可以拥有任意数量的广播接收器以对所有它感兴趣的通知信息予以响应。所有的接收器均继承自BroadcastReceiver基类。 
2、广播接收器没有用户界面。然而,它们可以启动一个activity来响应它们收到的信息,或者用NotificationManager来通知用户。通知可以用很多种方式来吸引用户的注意力──闪动背灯、震动、播放声音等等。一般来说是在状态栏上放一个持久的图标,用户可以打开它并获取消息。 


二、BroadcastReceiver事件分类 

1、系统广播事件,比如:ACTION_BOOT_COMPLETED(系统启动完成后触发),ACTION_TIME_CHANGED(系统时间改变时触发),ACTION_BATTERY_LOW(电量低时触发)等等。 

2、用户自定义的广播事件。 


三、BroadcastReceiver事件的编程流程 

1、注册广播事件:注册方式有两种,

一种是静态注册,就是在 AndroidManifest.xml文件中定义,注册的广播接收器必须要继承BroadcastReceiver类;

在AndroidManifest.xml中用标签生命注册,并在标签内用标签设置过滤器。

<receiver android:name="myRecevice">    //继承BroadcastReceiver,重写onReceiver方法<intent-filter>    <action android:name="com.dragon.net"></action> //使用过滤器,接收指定action广播</intent-filter></receiver>

另一种是动态注册,是在程序中使用 Context.registerReceiver注册,注册的广播接收器相当于一个匿名类。两种方式都需要IntentFIlter。

 

IntentFilter intentFilter = new IntentFilter();intentFilter.addAction(String);   //为BroadcastReceiver指定action,使之用于接收同action的广播registerReceiver(BroadcastReceiver,intentFilter);

  一般:在onStart中注册,onStop中取消unregisterReceiver 

  指定广播目标Action:Intent intent = new Intent(actionString); 

  并且可通过Intent携带消息 :intent.putExtra("msg", "hello,我通过广播发送消息了"); 

  发送广播消息:Context.sendBroadcast(intent )

 

2、发送广播事件:通过Context.sendBroadcast来发送,由Intent来传递注册时用到的Action。 

3、 接收广播事件:当发送的广播被接收器监听到后,会调用它的onReceive()方法,并将包含消息的Intent对象传给它。onReceive中代码的执行时间不要超过5s,否则Android会弹出超时dialog。

四、两类BroadcastReceiver

1、正常广播 Normal broadcasts(用 Context.sendBroadcast()发送)是完全异步的。它们都运行在一个未定义的顺序,通常是在同一时间。这样会更有效,但意味着receiver不能包含所要使用的结果或中止的API。  
2、有序广播 Ordered broadcasts(用 Context.sendOrderedBroadcast()发送)每次被发送到一个receiver。所谓有序,就是每个receiver执行后可以传播到下一个receiver,也可以完全中止传播??不传播给其他receiver。 而receiver运行的顺序可以通过matched intent-filter 里面的android:priority来控制,当priority优先级相同的时候,Receiver以任意的顺序运行。

 

PS:

下面举例说明了4种情况的广播事件:静态注册的系统广播事件、静态注册的用户自定义广播事件、动态注册的系统广播事件和动态注册的用户自定义广播事件。

1、创建广播接受者

 

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.util.Log;public class MyReceiver extends BroadcastReceiver {private static final String TAG = "MyReceiver";@Overridepublic void onReceive(Context context, Intent intent) {String msg = intent.getStringExtra("msg");Log.i(TAG, msg);}}
2、广播注册 

 

1)静态注册
静态注册是在AndroidManifest.xml文件中配置的,我们就来为MyReceiver注册一个广播地址:

<receiver android:name=".MyReceiver"><intent-filter><action android:name="android.intent.action.MY_BROADCAST"/><category android:name="android.intent.category.DEFAULT" /></intent-filter></receiver>
配置了以上信息之后,只要是android.intent.action.MY_BROADCAST这个地址的广播,MyReceiver都能够接收的到。


2)动态注册
动态注册需要在代码中动态的指定广播地址并注册,通常我们是在Activity或Service注册一个广播,下面我们就来看一下注册的代码:

 

MyReceiver receiver = new MyReceiver();IntentFilter filter = new IntentFilter();
filter.addAction("android.intent.action.MY_BROADCAST");registerReceiver(receiver, filter);

3)发送广播

 

 

    public void send(View view) {Intent intent = new Intent("android.intent.action.MY_BROADCAST");intent.putExtra("msg", "hello receiver.");sendBroadcast(intent);}

PS:

 

下面简单介绍下系统广播

下面是android系统中定义了很多标准的Broadcast Action来响应系统的广播事件(只列出一部分)

①ACTION_TIME_CHANGED(时间改变时触发)
②ACTION_BOOT_COMPLETED(系统启动完成后触发)--比如有些程序开机后启动就是用这种方式来实现的
③ACTION_PACKAGE_ADDED(添加包时触发)
④ACTION_BATTERY_CHANGED(电量低时触发)

 

/*** 系统静态注册广播消息接收器* * @author zuolongsnail* */
public class SystemReceiver extends BroadcastReceiver {@Overridepublic void onReceive(Context context, Intent intent) {if (intent.getAction().equals(Intent.ACTION_BATTERY_LOW)) {Log.e("SystemReceiver", "电量低提示");Toast.makeText(context, "您的手机电量偏低,请及时充电", Toast.LENGTH_SHORT).show();}}
}

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"package="com.byread" android:versionCode="1" android:versionName="1.0"><application android:icon="@drawable/icon" android:label="@string/app_name"><activity android:name=".MainActivity" 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=".SystemReceiver"><intent-filter><action android:name="android.intent.action.BATTERY_LOW" /></intent-filter></receiver></application>
</manifest>

 

五、普通广播和有序广播

上面的例子只是一个接收者来接收广播,如果有多个接收者都注册了相同的广播地址,又会是什么情况呢,能同时接收到同一条广播吗,相互之间会不会有干扰呢?

这就涉及到普通广播和有序广播的概念了。

1、Normal Broadcast(普通广播):Normal Broadcast是完全异步的,可以在同一时刻(逻辑上)被所有接收者接收到,消息传递的效率比较高。但缺点是接受者不能将处理结果传递给下一个接收者,并且无法终止Broadcast Intent的广播。
 
 2、Ordered Broadcast(有序广播):Ordered Broadcast的接收者将按预先声明的优先级依次接受Broadcast。如:A的级别高于B、B的级别高于C,那么Broadcast先传给A,再传给B,最后传给C。优先级别声明在<intent-filter.../>元素的android:priority属性中,数越大优先级别越高,取值范围为-1000-1000,优先级别也可以调用IntentFilter对象的setPriority()进行设置。OrderedBroadcast接收者可以终止Broadcast Intent的传播,BroadcastIntent的传播一旦终止,后面的接收者就无法接收到Broadcast。另外,OrderedBroadcast的接收者可以将数据传递给下一个接收者。如:A得到Broadcast后,可以往它的结果对象中存入数据,当Broadcast传给B时,B可以从A的结果对象中得到A存入的数据。

3、context提供的如下两个方法用于发送广播:
  sendBroadcast():发送Normal Broadcast
    sendOrderedBroadcast():发送OrderedBroadcast。
 
4、对于OrderedBroadcast而言,系统会根据接收者生命的优先级别顺序逐个执行接收者,优先接收到Broadcast的接收者可以终止Broadcast,调用BroadcastReceiver的abortBroadcast()方法即可终止Broadcast。如果Broadcast被前面的接收者终止,后面的接收者就再也无法获取到Broadcast。
 
5、不仅如此,对于OrderBroadcast而言,优先接收到Broadcast的接收者可以通过setResultExtras(Bundle)方法将处理结果存入Broadcast中,然后传给下一个接收者,下一个接收者通过代码:  Bundle bundle=getResultExtras(true)可以获取上一个接收者存入的数据。

实例:点击按钮,两个Receiver接收同一条广播,在logcat中打印出数据(按照Receiver的优先顺序,Receiver2先,Receiver1后)

Manifest:      

 

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"package="com.song"android:versionCode="1"android:versionName="1.0" ><uses-sdk android:minSdkVersion="8" /><applicationandroid:icon="@drawable/ic_launcher"android:label="@string/app_name" ><activityandroid:label="@string/app_name"android:name=".C48_BroadcastActivity" ><intent-filter ><action android:name="android.intent.action.MAIN" /><category android:name="android.intent.category.LAUNCHER" /></intent-filter><!--优先级的设定 MyReceiver2大于MyReceiver1,优先级的范围-1000~1000 --></activity><receiver android:name=".MyReceiver1"><intent-filter android:priority="200"><action android:name="com.song.123"/></intent-filter></receiver><receiver android:name=".MyReceiver2"><intent-filter android:priority="1000"><action android:name="com.song.123"/></intent-filter></receiver></application></manifest>

activity代码:

 

 

//发送广播,bundle绑上key为a的数据
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;public class C48_BroadcastActivity extends Activity {/** Called when the activity is first created. */Button button;@Overridepublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.main);button=(Button)findViewById(R.id.button);button.setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View v) {// TODO Auto-generated method stubIntent intent=new Intent("com.song.123");Bundle bundle=new Bundle();bundle.putString("a", "aaa");intent.putExtras(bundle);//有序广播sendOrderedBroadcast(intent, null);}});}
}
Receiver2

 

 

package com.song;
//优先接到广播,bundle绑上key为b的数据
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;public class MyReceiver2 extends BroadcastReceiver{@Overridepublic void onReceive(Context context, Intent intent) {// TODO Auto-generated method stubSystem.out.println("receiver2");
//		context.getSystemService(name);Bundle bundle=intent.getExtras();bundle.putString("b", "bbb");System.out.println("a="+bundle.get("a"));setResultExtras(bundle);//切断广播
//		abortBroadcast();     }}

Receiver1

 

 

package com.song;
//接收从receiver2传来的广播,包含key为a和b的数据
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;public class MyReceiver1 extends BroadcastReceiver{@Overridepublic void onReceive(Context context, Intent intent) {// TODO Auto-generated method stubSystem.out.println("receiver1");//要不要接受上一个广播接收器receiver2传来的的数据Bundle bundle=getResultExtras(true);System.out.println("a="+bundle.getString("a")+",b="+bundle.getString("b"));}}

根据上面的配置可以看出,该程序包括两个receiver,其中 Receiver2高,Receiver1低。如果Receiver2中的Receiver2zhabortBroadcast()注释了,那么程序Receiver1中将可以看到完整的信息了。

 

 

六、Service与BroadcastReceiver如何交互?

我们之前都是先启动了一个Activity,然后在Activity中启动服务。如果是这样,在启动服务时必须要先启动一个Activity。在很多时候这样做有些多余,我们现在可以利用Broadcast Receiver在Android系统启动时运行一个Activity。也许我们会从中得到一些启发,既然可以在Broadcast Receiver中启动Activity,为什么不能启动Service呢?说做就做,现在让我们来验证一下这个想法。

先编写一个服务类,这个服务类没什么特别的,仍然使用前面两节编写的MyService类即可。在AndroidManifest.xml文件中配置MyService类的代码也相同。

下面来完成最关键的一步,就是建立一个BroadcastReceiver,代码如下:

 

import android.content.BroadcastReceiver;  
import android.content.Context;  
import android.content.Intent;  public class StartupReceiver extends BroadcastReceiver  
{  @Override  public void onReceive(Context context, Intent intent)  {  //  启动一个Service  Intent serviceIntent = new Intent(context, MyService.class);          context.startService(serviceIntent);          Intent activityIntent = new Intent(context, MessageActivity.class);  //  要想在Service中启动Activity,必须设置如下标志  activityIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);  context.startActivity(activityIntent);  }  
} 

在StartupReceiver类的onReceive方法中完成了两项工作:启动服务和显示一个Activity来提示服务启动成功。 

 

AndroidManifest.xml文件的完整代码。

 

<?xml version="1.0" encoding="utf-8"?> 
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="net.blogjava.mobile.startupservice"android:versionCode="1" android:versionName="1.0"> <application android:icon="@drawable/icon" 
android:label="@string/app_name"> <activity android:name=".MessageActivity" 
android:theme="@android:style/Theme.Dialog"> <intent-filter>                  <category android:name="android.
intent.category.LAUNCHER" /> </intent-filter> </activity> <receiver android:name="StartupReceiver"> <intent-filter> <action android:name="android.
intent.action.BOOT_COMPLETED" /> <category android:name="android.
intent.category.LAUNCHER" /> </intent-filter> </receiver> <service android:enabled="true" android:name=".MyService" /> </application> <uses-sdk android:minSdkVersion="3" /> <uses-permission android:name="android.
permission.RECEIVE_BOOT_COMPLETED" /> 
</manifest> 

 

 

PS:

开机自动运行service

我们经常会有这样的应用场合,比如消息推送服务,需要实现开机启动的功能。要实现这个功能,我们就可以订阅系统“启动完成(BOOT_COMPLETED)”这条广播,接收到这条广播后我们就可以启动自己的服务了;

上面实例其实和开机启动服务差不多了,下面我们在说说开机启动服务。
Receiver :

 

public class BootCompleteReceiver extends BroadcastReceiver {private static final String TAG = "BootCompleteReceiver";@Overridepublic void onReceive(Context context, Intent intent) {Intent service = new Intent(context, MsgPushService.class);context.startService(service);Log.i(TAG, "Boot Complete. Starting MsgPushService...");}}

 

 

Service :

public class MsgPushService extends Service {private static final String TAG = "MsgPushService";@Overridepublic void onCreate() {super.onCreate();Log.i(TAG, "onCreate called.");}@Overridepublic int onStartCommand(Intent intent, int flags, int startId) {Log.i(TAG, "onStartCommand called.");return super.onStartCommand(intent, flags, startId);}@Overridepublic IBinder onBind(Intent arg0) {return null;}
}
AndroidManifest 
        <!-- 开机广播接受者 --><receiver android:name=".BootCompleteReceiver"><intent-filter><!-- 注册开机广播地址--><action android:name="android.intent.action.BOOT_COMPLETED"/><category android:name="android.intent.category.DEFAULT" /></intent-filter></receiver><!-- 消息推送服务 --><service android:name=".MsgPushService"/>

PS:

最后在说说Broadcast的生命周期

  1、一个BroadcastReceiver 对象只有在被调用onReceive(Context, Intent)的才有效的,当从该函数返回后,该对象就无效的了,结束生命周期。

  因此从这个特征可以看出,在所调用的onReceive(Context, Intent)函数里,不能有过于耗时的操作,不能使用线程来执行。对于耗时的操作,请start service来完成。因为当得到其他异步操作所返回的结果时,BroadcastReceiver 可能已经无效了。

2、一个Broadcast receiver只有一个回调方法:

void onReceive(Context curContext, Intent broadcastMsg)

当Broadcast receiver接收到一条广播信息,android会调用它的onReceive()方法,并传递给它一个包含广播信息的intent对象。当Broadcast receiver在执行这个方法时可以认为它是活动的,onReceive()方法返回时,它便终止了。

一个包含活动Broadcast receiver的进程会被系统保护以避免被终止。但是如果进程不包含任何活动组件,那么当它占用的内存要用于其它进程时,系统任何时候都可以终止运行该进程。

当应答一条广播信息十分耗时,而另一个线程必须执行某个任务时会出现一个问题。试想一下,如果onReceive()方法产生一个线程然后返回,那么整个进程,包括新的线程会被认为是不活动的(除非在进程中还有其它活动的组件),该进程就有被系统终止运行的危险。解决这个问题的办法就是在onReceive()方法中启动一个服务,让这个服务做那样的工作,这样系统就会知道进程中有活动的组件而不会停止进程。

 

这篇关于Android四大组件Broadcast Receiver详解的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/944818

相关文章

SQL BETWEEN 语句的基本用法详解

《SQLBETWEEN语句的基本用法详解》SQLBETWEEN语句是一个用于在SQL查询中指定查询条件的重要工具,它允许用户指定一个范围,用于筛选符合特定条件的记录,本文将详细介绍BETWEEN语... 目录概述BETWEEN 语句的基本用法BETWEEN 语句的示例示例 1:查询年龄在 20 到 30 岁

CSS place-items: center解析与用法详解

《CSSplace-items:center解析与用法详解》place-items:center;是一个强大的CSS简写属性,用于同时控制网格(Grid)和弹性盒(Flexbox)... place-items: center; 是一个强大的 css 简写属性,用于同时控制 网格(Grid) 和 弹性盒(F

spring中的ImportSelector接口示例详解

《spring中的ImportSelector接口示例详解》Spring的ImportSelector接口用于动态选择配置类,实现条件化和模块化配置,关键方法selectImports根据注解信息返回... 目录一、核心作用二、关键方法三、扩展功能四、使用示例五、工作原理六、应用场景七、自定义实现Impor

一文深入详解Python的secrets模块

《一文深入详解Python的secrets模块》在构建涉及用户身份认证、权限管理、加密通信等系统时,开发者最不能忽视的一个问题就是“安全性”,Python在3.6版本中引入了专门面向安全用途的secr... 目录引言一、背景与动机:为什么需要 secrets 模块?二、secrets 模块的核心功能1. 基

一文详解MySQL如何设置自动备份任务

《一文详解MySQL如何设置自动备份任务》设置自动备份任务可以确保你的数据库定期备份,防止数据丢失,下面我们就来详细介绍一下如何使用Bash脚本和Cron任务在Linux系统上设置MySQL数据库的自... 目录1. 编写备份脚本1.1 创建并编辑备份脚本1.2 给予脚本执行权限2. 设置 Cron 任务2

一文详解如何在idea中快速搭建一个Spring Boot项目

《一文详解如何在idea中快速搭建一个SpringBoot项目》IntelliJIDEA作为Java开发者的‌首选IDE‌,深度集成SpringBoot支持,可一键生成项目骨架、智能配置依赖,这篇文... 目录前言1、创建项目名称2、勾选需要的依赖3、在setting中检查maven4、编写数据源5、开启热

Python常用命令提示符使用方法详解

《Python常用命令提示符使用方法详解》在学习python的过程中,我们需要用到命令提示符(CMD)进行环境的配置,:本文主要介绍Python常用命令提示符使用方法的相关资料,文中通过代码介绍的... 目录一、python环境基础命令【Windows】1、检查Python是否安装2、 查看Python的安

HTML5 搜索框Search Box详解

《HTML5搜索框SearchBox详解》HTML5的搜索框是一个强大的工具,能够有效提升用户体验,通过结合自动补全功能和适当的样式,可以创建出既美观又实用的搜索界面,这篇文章给大家介绍HTML5... html5 搜索框(Search Box)详解搜索框是一个用于输入查询内容的控件,通常用于网站或应用程

Python中使用uv创建环境及原理举例详解

《Python中使用uv创建环境及原理举例详解》uv是Astral团队开发的高性能Python工具,整合包管理、虚拟环境、Python版本控制等功能,:本文主要介绍Python中使用uv创建环境及... 目录一、uv工具简介核心特点:二、安装uv1. 通过pip安装2. 通过脚本安装验证安装:配置镜像源(可

C++ 函数 strftime 和时间格式示例详解

《C++函数strftime和时间格式示例详解》strftime是C/C++标准库中用于格式化日期和时间的函数,定义在ctime头文件中,它将tm结构体中的时间信息转换为指定格式的字符串,是处理... 目录C++ 函数 strftipythonme 详解一、函数原型二、功能描述三、格式字符串说明四、返回值五