当前位置: 首页 > article >正文

详解 Android 中 BroadcastReceiver

要创建自己的BroadcastReceiver对象,我们需要继承android.content.BroadcastReceiver,并实现其onReceive方法。

下面我们就创建一个名为MyReceiver广播接收者:

[java]  view plain copy

  1. package com.scott.receiver;

  2. import android.content.BroadcastReceiver;

  3. import android.content.Context;

  4. import android.content.Intent;

  5. import android.util.Log;

  6. public class MyReceiver extends BroadcastReceiver {

  7. private static final String TAG = “MyReceiver”;

  8. @Override

  9. public void onReceive(Context context, Intent intent) {

  10. String msg = intent.getStringExtra(“msg”);

  11. Log.i(TAG, msg);

  12. }

  13. }

在onReceive方法内,我们可以获取随广播而来的Intent中的数据,这非常重要,就像无线电一样,包含很多有用的信息。

在创建完我们的BroadcastReceiver之后,还不能够使它进入工作状态,我们需要为它注册一个指定的广播地址。没有注册广播地址的BroadcastReceiver就像一个缺少选台按钮的收音机,虽然功能俱备,但也无法收到电台的信号。下面我们就来介绍一下如何为BroadcastReceiver注册广播地址。

静态注册

========

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

[html]  view plain copy

  1. <receiver android:name=“.MyReceiver”>

  2. <intent-filter>

  3. <action android:name=“android.intent.action.MY_BROADCAST”/>

  4. <category android:name=“android.intent.category.DEFAULT” />

  5. </intent-filter>

  6. </receiver>

配置了以上信息之后,只要是android.intent.action.MY_BROADCAST这个地址的广播,MyReceiver都能够接收的到。注意,这种方式的注册是常驻型的,也就是说当应用关闭后,如果有广播信息传来,MyReceiver也会被系统调用而自动运行。

动态注册

========

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

[java]  view plain copy

  1. MyReceiver receiver = new MyReceiver();

  2. IntentFilter filter = new IntentFilter();

  3. filter.addAction(“android.intent.action.MY_BROADCAST”);

  4. registerReceiver(receiver, filter);

注意,registerReceiver是android.content.ContextWrapper类中的方法,Activity和Service都继承了ContextWrapper,所以可以直接调用。在实际应用中,我们在Activity或Service中注册了一个BroadcastReceiver,当这个Activity或Service被销毁时如果没有解除注册,系统会报一个异常,提示我们是否忘记解除注册了。所以,记得在特定的地方执行解除注册操作:

[java]  view plain copy

  1. @Override

  2. protected void onDestroy() {

  3. super.onDestroy();

  4. unregisterReceiver(receiver);

  5. }

执行这样行代码就可以解决问题了。注意,这种注册方式与静态注册相反,不是常驻型的,也就是说广播会跟随程序的生命周期。

我们可以根据以上任意一种方法完成注册,当注册完成之后,这个接收者就可以正常工作了。我们可以用以下方式向其发送一条广播:

[java]  view plain copy

  1. public void send(View view) {

  2. Intent intent = new Intent(“android.intent.action.MY_BROADCAST”);

  3. intent.putExtra(“msg”, “hello receiver.”);

  4. sendBroadcast(intent);

  5. }

注意,sendBroadcast也是android.content.ContextWrapper类中的方法,它可以将一个指定地址和参数信息的Intent对象以广播的形式发送出去。

点击发送按钮,执行send方法,控制台打印如下:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

看到这样的打印信息,表明我们的广播已经发出去了,并且被MyReceiver准确无误的接收到了。

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

普通广播(Normal Broadcast)

==========================

普通广播对于多个接收者来说是完全异步的,通常每个接收者都无需等待即可以接收到广播,接收者相互之间不会有影响。对于这种广播,接收者无法终止广播,即无法阻止其他接收者的接收动作。

为了验证以上论断,我们新建三个BroadcastReceiver,演示一下这个过程,FirstReceiver、SecondReceiver和ThirdReceiver的代码如下:

[java]  view plain copy

  1. package com.scott.receiver;

  2. import android.content.BroadcastReceiver;

  3. import android.content.Context;

  4. import android.content.Intent;

  5. import android.util.Log;

  6. public class FirstReceiver extends BroadcastReceiver {

  7. private static final String TAG = “NormalBroadcast”;

  8. @Override

  9. public void onReceive(Context context, Intent intent) {

  10. String msg = intent.getStringExtra(“msg”);

  11. Log.i(TAG, "FirstReceiver: " + msg);

  12. }

  13. }

[java]  view plain copy

  1. public class SecondReceiver extends BroadcastReceiver {

  2. private static final String TAG = “NormalBroadcast”;

  3. @Override

  4. public void onReceive(Context context, Intent intent) {

  5. String msg = intent.getStringExtra(“msg”);

  6. Log.i(TAG, "SecondReceiver: " + msg);

  7. }

  8. }

[java]  view plain copy

  1. public class ThirdReceiver extends BroadcastReceiver {

  2. private static final String TAG = “NormalBroadcast”;

  3. @Override

  4. public void onReceive(Context context, Intent intent) {

  5. String msg = intent.getStringExtra(“msg”);

  6. Log.i(TAG, "ThirdReceiver: " + msg);

  7. }

  8. }

然后再次点击发送按钮,发送一条广播,控制台打印如下:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

看来这三个接收者都接收到这条广播了,我们稍微修改一下三个接收者,在onReceive方法的最后一行添加以下代码,试图终止广播:

[java]  view plain copy

  1. abortBroadcast();

再次点击发送按钮,我们会发现,控制台中三个接收者仍然都打印了自己的日志,表明接收者并不能终止广播。

有序广播(Ordered Broadcast)

===========================

有序广播比较特殊,它每次只发送到优先级较高的接收者那里,然后由优先级高的接受者再传播到优先级低的接收者那里,优先级高的接收者有能力终止这个广播。

为了演示有序广播的流程,我们修改一下上面三个接收者的代码,如下:

[java]  view plain copy

  1. package com.scott.receiver;

  2. import android.content.BroadcastReceiver;

  3. import android.content.Context;

  4. import android.content.Intent;

  5. import android.os.Bundle;

  6. import android.util.Log;

  7. public class FirstReceiver extends BroadcastReceiver {

  8. private static final String TAG = “OrderedBroadcast”;

  9. @Override

  10. public void onReceive(Context context, Intent intent) {

  11. String msg = intent.getStringExtra(“msg”);

  12. Log.i(TAG, "FirstReceiver: " + msg);

  13. Bundle bundle = new Bundle();

  14. bundle.putString(“msg”, msg + “@FirstReceiver”);

  15. setResultExtras(bundle);

  16. }

  17. }

[java]  view plain copy

  1. public class SecondReceiver extends BroadcastReceiver {

  2. private static final String TAG = “OrderedBroadcast”;

  3. @Override

  4. public void onReceive(Context context, Intent intent) {

  5. String msg = getResultExtras(true).getString(“msg”);

  6. Log.i(TAG, "SecondReceiver: " + msg);

  7. Bundle bundle = new Bundle();

  8. bundle.putString(“msg”, msg + “@SecondReceiver”);

  9. setResultExtras(bundle);

  10. }

  11. }

[java]  view plain copy

  1. public class ThirdReceiver extends BroadcastReceiver {

  2. private static final String TAG = “OrderedBroadcast”;

  3. @Override

  4. public void onReceive(Context context, Intent intent) {

  5. String msg = getResultExtras(true).getString(“msg”);

  6. Log.i(TAG, "ThirdReceiver: " + msg);

  7. }

  8. }

我们注意到,在FirstReceiver和SecondReceiver中最后都使用了setResultExtras方法将一个Bundle对象设置为结果集对象,传递到下一个接收者那里,这样以来,优先级低的接收者可以用getResultExtras获取到最新的经过处理的信息集合。

代码改完之后,我们需要为三个接收者注册广播地址,我们修改一下AndroidMainfest.xml文件:

[html]  view plain copy

  1. <receiver android:name=“.FirstReceiver”>

  2. <intent-filter android:priority=“1000”>

  3. <action android:name=“android.intent.action.MY_BROADCAST”/>

  4. <category android:name=“android.intent.category.DEFAULT” />

  5. </intent-filter>

  6. </receiver>

  7. <receiver android:name=“.SecondReceiver”>

  8. <intent-filter android:priority=“999”>

  9. <action android:name=“android.intent.action.MY_BROADCAST”/>

  10. <category android:name=“android.intent.category.DEFAULT” />

  11. </intent-filter>

  12. </receiver>

  13. <receiver android:name=“.ThirdReceiver”>

  14. <intent-filter android:priority=“998”>

  15. <action android:name=“android.intent.action.MY_BROADCAST”/>

  16. <category android:name=“android.intent.category.DEFAULT” />

  17. </intent-filter>

  18. </receiver>

我们看到,现在这三个接收者的多了一个android:priority属性,并且依次减小。这个属性的范围在-1000到1000,数值越大,优先级越高。

现在,修改一下发送广播的代码,如下:

[java]  view plain copy

  1. public void send(View view) {

  2. Intent intent = new Intent(“android.intent.action.MY_BROADCAST”);

  3. intent.putExtra(“msg”, “hello receiver.”);

  4. sendOrderedBroadcast(intent, “scott.permission.MY_BROADCAST_PERMISSION”);

  5. }

注意,使用sendOrderedBroadcast方法发送有序广播时,需要一个权限参数,如果为null则表示不要求接收者声明指定的权限,如果不为null,则表示接收者若要接收此广播,需声明指定权限。这样做是从安全角度考虑的,例如系统的短信就是有序广播的形式,一个应用可能是具有拦截垃圾短信的功能,当短信到来时它可以先接受到短信广播,必要时终止广播传递,这样的软件就必须声明接收短信的权限。

所以我们在AndroidMainfest.xml中定义一个权限:

[html]  view plain copy

  1. <permission android:protectionLevel=“normal”

  2. android:name=“scott.permission.MY_BROADCAST_PERMISSION” />

然后声明使用了此权限:

[html]  view plain copy

  1. <uses-permission android:name=“scott.permission.MY_BROADCAST_PERMISSION” />

然后我们点击发送按钮发送一条广播,控制台打印如下:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

我们看到接收是按照顺序的,第一个和第二个都在结果集中加入了自己的标记,并且向优先级低的接收者传递下去。

既然是顺序传递,试着终止这种传递,看一看效果如何,我们修改FirstReceiver的代码,在onReceive的最后一行添加以下代码:

[java]  view plain copy

  1. abortBroadcast();

然后再次运行程序,控制台打印如下:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

此次,只有第一个接收者执行了,其它两个都没能执行,因为广播被第一个接收者终止了。

上面就是BroadcastReceiver的介绍,下面我将会举几个常见的例子加深一下大家对广播的理解和应用:

1.开机启动服务

我们经常会有这样的应用场合,比如消息推送服务,需要实现开机启动的功能。要实现这个功能,我们就可以订阅系统“启动完成”这条广播,接收到这条广播后我们就可以启动自己的服务了。我们来看一下BootCompleteReceiver和MsgPushService的具体实现:

[java]  view plain copy

  1. package com.scott.receiver;

  2. import android.content.BroadcastReceiver;

  3. import android.content.Context;

  4. import android.content.Intent;

  5. import android.util.Log;

  6. public class BootCompleteReceiver extends BroadcastReceiver {

  7. private static final String TAG = “BootCompleteReceiver”;

  8. @Override

  9. public void onReceive(Context context, Intent intent) {

  10. Intent service = new Intent(context, MsgPushService.class);

  11. context.startService(service);

  12. Log.i(TAG, “Boot Complete. Starting MsgPushService…”);

  13. }

  14. }

[java]  view plain copy

  1. package com.scott.receiver;

  2. import android.app.Service;

  3. import android.content.Intent;

  4. import android.os.IBinder;

  5. import android.util.Log;

  6. public class MsgPushService extends Service {

  7. private static final String TAG = “MsgPushService”;

  8. @Override

  9. public void onCreate() {

  10. super.onCreate();

  11. Log.i(TAG, “onCreate called.”);

  12. }

  13. @Override

  14. public int onStartCommand(Intent intent, int flags, int startId) {

  15. Log.i(TAG, “onStartCommand called.”);

  16. return super.onStartCommand(intent, flags, startId);

  17. }

  18. @Override

  19. public IBinder onBind(Intent arg0) {

  20. return null;

  21. }

  22. }

然后我们需要在AndroidManifest.xml中配置相关信息:

[html]  view plain copy

  1. <receiver android:name=“.BootCompleteReceiver”>

  2. <intent-filter>

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则近万的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

img

img

img

img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:Android)

最后

这里附上上述的技术体系图相关的几十套腾讯、头条、阿里、美团等公司2021年的面试题,把技术点整理成了视频和PDF(实际上比预期多花了不少精力),包含知识脉络 + 诸多细节,由于篇幅有限,这里以图片的形式给大家展示一部分。

相信它会给大家带来很多收获:

img

当程序员容易,当一个优秀的程序员是需要不断学习的,从初级程序员到高级程序员,从初级架构师到资深架构师,或者走向管理,从技术经理到技术总监,每个阶段都需要掌握不同的能力。早早确定自己的职业方向,才能在工作和能力提升中甩开同龄人。

  • 无论你现在水平怎么样一定要 持续学习 没有鸡汤,别人看起来的毫不费力,其实费了很大力,这四个字就是我的建议!!!
  • 我希望每一个努力生活的IT工程师,都会得到自己想要的,因为我们很辛苦,我们应得的。

当我们在抱怨环境,抱怨怀才不遇的时候,没有别的原因,一定是你做的还不够好!

《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》,点击传送门即可获取!

以上Android开发知识点,真正体系化!**

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:Android)

最后

这里附上上述的技术体系图相关的几十套腾讯、头条、阿里、美团等公司2021年的面试题,把技术点整理成了视频和PDF(实际上比预期多花了不少精力),包含知识脉络 + 诸多细节,由于篇幅有限,这里以图片的形式给大家展示一部分。

相信它会给大家带来很多收获:

[外链图片转存中…(img-AT4RlKKA-1712052813043)]

当程序员容易,当一个优秀的程序员是需要不断学习的,从初级程序员到高级程序员,从初级架构师到资深架构师,或者走向管理,从技术经理到技术总监,每个阶段都需要掌握不同的能力。早早确定自己的职业方向,才能在工作和能力提升中甩开同龄人。

  • 无论你现在水平怎么样一定要 持续学习 没有鸡汤,别人看起来的毫不费力,其实费了很大力,这四个字就是我的建议!!!
  • 我希望每一个努力生活的IT工程师,都会得到自己想要的,因为我们很辛苦,我们应得的。

当我们在抱怨环境,抱怨怀才不遇的时候,没有别的原因,一定是你做的还不够好!

《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》,点击传送门即可获取!
http://www.lryc.cn/news/2417235.html

相关文章:

  • 用spss进行主成分分析
  • php fakepath,chrome上传图片 路径为c:/fakepath的解决办法
  • 常见编码方式之间的区别
  • 经典算法研究系列:八、再谈启发式搜索算法
  • IEEE会议排名(转载)
  • Libsvm使用笔记【matlab】
  • Wireshark 提示和技巧 | TCP Reassembly
  • 体验ChitGPT AI大模型生成生成拉格朗日运动轨迹和具体实践案例
  • 堆栈溢出及其原因
  • python编写小游戏的代码,python游戏编程代码大全
  • 异步任务(AsyncTask)
  • 电脑死机是什么原因及解决方法
  • 我是巢皮...
  • Paypal开发者中心获取“ClientId”和“ClientSecret”参数
  • objectARX自用总结
  • HTK学习笔记(一)
  • CLSID应用
  • MPC模型预测控制及在Matlab中实现函数定义
  • U盘全新安装windows2003系统
  • 10款用于查询IP地址的工具网站
  • DirectSound 与Waveout的区别
  • 实验误差分析大全,实验员必备!
  • Wireshark过滤总结
  • 【读码JDK】-java.lang包介绍
  • java启动参数xmm_更快的方法来测试xmm / ymm寄存器是否为零?
  • 敏捷软件开发
  • .mp4视频测试地址
  • Java IO流操作汇总: inputStream 和 outputStream
  • DRM-widevine 总结
  • 电脑提示msvcp110.dll丢失修复方法,总结四个有效的方法