要创建自己的BroadcastReceiver对象,我们需要继承android.content.BroadcastReceiver,并实现其onReceive方法。
下面我们就创建一个名为MyReceiver广播接收者:
[java] view plain copy
-
package com.scott.receiver;
-
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”;
-
@Override
-
public void onReceive(Context context, Intent intent) {
-
String msg = intent.getStringExtra(“msg”);
-
Log.i(TAG, msg);
-
}
-
}
在onReceive方法内,我们可以获取随广播而来的Intent中的数据,这非常重要,就像无线电一样,包含很多有用的信息。
在创建完我们的BroadcastReceiver之后,还不能够使它进入工作状态,我们需要为它注册一个指定的广播地址。没有注册广播地址的BroadcastReceiver就像一个缺少选台按钮的收音机,虽然功能俱备,但也无法收到电台的信号。下面我们就来介绍一下如何为BroadcastReceiver注册广播地址。
静态注册
========
静态注册是在AndroidManifest.xml文件中配置的,我们就来为MyReceiver注册一个广播地址:
[html] view plain copy
-
<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都能够接收的到。注意,这种方式的注册是常驻型的,也就是说当应用关闭后,如果有广播信息传来,MyReceiver也会被系统调用而自动运行。
动态注册
========
动态注册需要在代码中动态的指定广播地址并注册,通常我们是在Activity或Service注册一个广播,下面我们就来看一下注册的代码:
[java] view plain copy
-
MyReceiver receiver = new MyReceiver();
-
IntentFilter filter = new IntentFilter();
-
filter.addAction(“android.intent.action.MY_BROADCAST”);
-
registerReceiver(receiver, filter);
注意,registerReceiver是android.content.ContextWrapper类中的方法,Activity和Service都继承了ContextWrapper,所以可以直接调用。在实际应用中,我们在Activity或Service中注册了一个BroadcastReceiver,当这个Activity或Service被销毁时如果没有解除注册,系统会报一个异常,提示我们是否忘记解除注册了。所以,记得在特定的地方执行解除注册操作:
[java] view plain copy
-
@Override
-
protected void onDestroy() {
-
super.onDestroy();
-
unregisterReceiver(receiver);
-
}
执行这样行代码就可以解决问题了。注意,这种注册方式与静态注册相反,不是常驻型的,也就是说广播会跟随程序的生命周期。
我们可以根据以上任意一种方法完成注册,当注册完成之后,这个接收者就可以正常工作了。我们可以用以下方式向其发送一条广播:
[java] view plain copy
-
public void send(View view) {
-
Intent intent = new Intent(“android.intent.action.MY_BROADCAST”);
-
intent.putExtra(“msg”, “hello receiver.”);
-
sendBroadcast(intent);
-
}
注意,sendBroadcast也是android.content.ContextWrapper类中的方法,它可以将一个指定地址和参数信息的Intent对象以广播的形式发送出去。
点击发送按钮,执行send方法,控制台打印如下:
看到这样的打印信息,表明我们的广播已经发出去了,并且被MyReceiver准确无误的接收到了。
上面的例子只是一个接收者来接收广播,如果有多个接收者都注册了相同的广播地址,又会是什么情况呢,能同时接收到同一条广播吗,相互之间会不会有干扰呢?这就涉及到普通广播和有序广播的概念了。
普通广播(Normal Broadcast)
==========================
普通广播对于多个接收者来说是完全异步的,通常每个接收者都无需等待即可以接收到广播,接收者相互之间不会有影响。对于这种广播,接收者无法终止广播,即无法阻止其他接收者的接收动作。
为了验证以上论断,我们新建三个BroadcastReceiver,演示一下这个过程,FirstReceiver、SecondReceiver和ThirdReceiver的代码如下:
[java] view plain copy
-
package com.scott.receiver;
-
import android.content.BroadcastReceiver;
-
import android.content.Context;
-
import android.content.Intent;
-
import android.util.Log;
-
public class FirstReceiver extends BroadcastReceiver {
-
private static final String TAG = “NormalBroadcast”;
-
@Override
-
public void onReceive(Context context, Intent intent) {
-
String msg = intent.getStringExtra(“msg”);
-
Log.i(TAG, "FirstReceiver: " + msg);
-
}
-
}
[java] view plain copy
-
public class SecondReceiver extends BroadcastReceiver {
-
private static final String TAG = “NormalBroadcast”;
-
@Override
-
public void onReceive(Context context, Intent intent) {
-
String msg = intent.getStringExtra(“msg”);
-
Log.i(TAG, "SecondReceiver: " + msg);
-
}
-
}
[java] view plain copy
-
public class ThirdReceiver extends BroadcastReceiver {
-
private static final String TAG = “NormalBroadcast”;
-
@Override
-
public void onReceive(Context context, Intent intent) {
-
String msg = intent.getStringExtra(“msg”);
-
Log.i(TAG, "ThirdReceiver: " + msg);
-
}
-
}
然后再次点击发送按钮,发送一条广播,控制台打印如下:
看来这三个接收者都接收到这条广播了,我们稍微修改一下三个接收者,在onReceive方法的最后一行添加以下代码,试图终止广播:
[java] view plain copy
- abortBroadcast();
再次点击发送按钮,我们会发现,控制台中三个接收者仍然都打印了自己的日志,表明接收者并不能终止广播。
有序广播(Ordered Broadcast)
===========================
有序广播比较特殊,它每次只发送到优先级较高的接收者那里,然后由优先级高的接受者再传播到优先级低的接收者那里,优先级高的接收者有能力终止这个广播。
为了演示有序广播的流程,我们修改一下上面三个接收者的代码,如下:
[java] view plain copy
-
package com.scott.receiver;
-
import android.content.BroadcastReceiver;
-
import android.content.Context;
-
import android.content.Intent;
-
import android.os.Bundle;
-
import android.util.Log;
-
public class FirstReceiver extends BroadcastReceiver {
-
private static final String TAG = “OrderedBroadcast”;
-
@Override
-
public void onReceive(Context context, Intent intent) {
-
String msg = intent.getStringExtra(“msg”);
-
Log.i(TAG, "FirstReceiver: " + msg);
-
Bundle bundle = new Bundle();
-
bundle.putString(“msg”, msg + “@FirstReceiver”);
-
setResultExtras(bundle);
-
}
-
}
[java] view plain copy
-
public class SecondReceiver extends BroadcastReceiver {
-
private static final String TAG = “OrderedBroadcast”;
-
@Override
-
public void onReceive(Context context, Intent intent) {
-
String msg = getResultExtras(true).getString(“msg”);
-
Log.i(TAG, "SecondReceiver: " + msg);
-
Bundle bundle = new Bundle();
-
bundle.putString(“msg”, msg + “@SecondReceiver”);
-
setResultExtras(bundle);
-
}
-
}
[java] view plain copy
-
public class ThirdReceiver extends BroadcastReceiver {
-
private static final String TAG = “OrderedBroadcast”;
-
@Override
-
public void onReceive(Context context, Intent intent) {
-
String msg = getResultExtras(true).getString(“msg”);
-
Log.i(TAG, "ThirdReceiver: " + msg);
-
}
-
}
我们注意到,在FirstReceiver和SecondReceiver中最后都使用了setResultExtras方法将一个Bundle对象设置为结果集对象,传递到下一个接收者那里,这样以来,优先级低的接收者可以用getResultExtras获取到最新的经过处理的信息集合。
代码改完之后,我们需要为三个接收者注册广播地址,我们修改一下AndroidMainfest.xml文件:
[html] view plain copy
-
<receiver android:name=“.FirstReceiver”>
-
<intent-filter android:priority=“1000”>
-
<action android:name=“android.intent.action.MY_BROADCAST”/>
-
<category android:name=“android.intent.category.DEFAULT” />
-
</intent-filter>
-
</receiver>
-
<receiver android:name=“.SecondReceiver”>
-
<intent-filter android:priority=“999”>
-
<action android:name=“android.intent.action.MY_BROADCAST”/>
-
<category android:name=“android.intent.category.DEFAULT” />
-
</intent-filter>
-
</receiver>
-
<receiver android:name=“.ThirdReceiver”>
-
<intent-filter android:priority=“998”>
-
<action android:name=“android.intent.action.MY_BROADCAST”/>
-
<category android:name=“android.intent.category.DEFAULT” />
-
</intent-filter>
-
</receiver>
我们看到,现在这三个接收者的多了一个android:priority属性,并且依次减小。这个属性的范围在-1000到1000,数值越大,优先级越高。
现在,修改一下发送广播的代码,如下:
[java] view plain copy
-
public void send(View view) {
-
Intent intent = new Intent(“android.intent.action.MY_BROADCAST”);
-
intent.putExtra(“msg”, “hello receiver.”);
-
sendOrderedBroadcast(intent, “scott.permission.MY_BROADCAST_PERMISSION”);
-
}
注意,使用sendOrderedBroadcast方法发送有序广播时,需要一个权限参数,如果为null则表示不要求接收者声明指定的权限,如果不为null,则表示接收者若要接收此广播,需声明指定权限。这样做是从安全角度考虑的,例如系统的短信就是有序广播的形式,一个应用可能是具有拦截垃圾短信的功能,当短信到来时它可以先接受到短信广播,必要时终止广播传递,这样的软件就必须声明接收短信的权限。
所以我们在AndroidMainfest.xml中定义一个权限:
[html] view plain copy
-
<permission android:protectionLevel=“normal”
-
android:name=“scott.permission.MY_BROADCAST_PERMISSION” />
然后声明使用了此权限:
[html] view plain copy
- <uses-permission android:name=“scott.permission.MY_BROADCAST_PERMISSION” />
然后我们点击发送按钮发送一条广播,控制台打印如下:
我们看到接收是按照顺序的,第一个和第二个都在结果集中加入了自己的标记,并且向优先级低的接收者传递下去。
既然是顺序传递,试着终止这种传递,看一看效果如何,我们修改FirstReceiver的代码,在onReceive的最后一行添加以下代码:
[java] view plain copy
- abortBroadcast();
然后再次运行程序,控制台打印如下:
此次,只有第一个接收者执行了,其它两个都没能执行,因为广播被第一个接收者终止了。
上面就是BroadcastReceiver的介绍,下面我将会举几个常见的例子加深一下大家对广播的理解和应用:
1.开机启动服务
我们经常会有这样的应用场合,比如消息推送服务,需要实现开机启动的功能。要实现这个功能,我们就可以订阅系统“启动完成”这条广播,接收到这条广播后我们就可以启动自己的服务了。我们来看一下BootCompleteReceiver和MsgPushService的具体实现:
[java] view plain copy
-
package com.scott.receiver;
-
import android.content.BroadcastReceiver;
-
import android.content.Context;
-
import android.content.Intent;
-
import android.util.Log;
-
public class BootCompleteReceiver extends BroadcastReceiver {
-
private static final String TAG = “BootCompleteReceiver”;
-
@Override
-
public void onReceive(Context context, Intent intent) {
-
Intent service = new Intent(context, MsgPushService.class);
-
context.startService(service);
-
Log.i(TAG, “Boot Complete. Starting MsgPushService…”);
-
}
-
}
[java] view plain copy
-
package com.scott.receiver;
-
import android.app.Service;
-
import android.content.Intent;
-
import android.os.IBinder;
-
import android.util.Log;
-
public class MsgPushService extends Service {
-
private static final String TAG = “MsgPushService”;
-
@Override
-
public void onCreate() {
-
super.onCreate();
-
Log.i(TAG, “onCreate called.”);
-
}
-
@Override
-
public int onStartCommand(Intent intent, int flags, int startId) {
-
Log.i(TAG, “onStartCommand called.”);
-
return super.onStartCommand(intent, flags, startId);
-
}
-
@Override
-
public IBinder onBind(Intent arg0) {
-
return null;
-
}
-
}
然后我们需要在AndroidManifest.xml中配置相关信息:
[html] view plain copy
-
<receiver android:name=“.BootCompleteReceiver”>
-
<intent-filter>
先自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则近万的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《Android移动开发全套学习资料》送给大家,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频
如果你觉得这些内容对你有帮助,可以扫码领取!!!!
作者2013年从java开发,转做Android开发,在小厂待过,也去过华为,OPPO等大厂待过,18年四月份进了阿里一直到现在。
参与过不少面试,也当面试官 面试过很多人。深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长,不成体系的学习效果低效漫长,而且极易碰到天花板技术停滞不前!
我整理了一份阿里P7级别的最系统的Android开发主流技术,特别适合有3-5年以上经验的小伙伴深入学习提升。
主要包括阿里,以及字节跳动,腾讯,华为,小米,等一线互联网公司主流架构技术。如果你想深入系统学习Android开发,成为一名合格的高级工程师,可以收藏一下这些Android进阶技术选型
我搜集整理过这几年阿里,以及腾讯,字节跳动,华为,小米等公司的面试题,把面试的要求和技术点梳理成一份大而全的“ Android架构师”面试 Xmind(实际上比预期多花了不少精力),包含知识脉络 + 分支细节。
Java语言与原理;
大厂,小厂。Android面试先看你熟不熟悉Java语言
高级UI与自定义view;
自定义view,Android开发的基本功。
性能调优;
数据结构算法,设计模式。都是这里面的关键基础和重点需要熟练的。
NDK开发;
未来的方向,高薪必会。
前沿技术;
组件化,热升级,热修复,框架设计
网上学习 Android的资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。希望这份系统化的技术体系对大家有一个方向参考。
我在搭建这些技术框架的时候,还整理了系统的高级进阶教程,会比自己碎片化学习效果强太多,CodeChina上可见;
当然,想要深入学习并掌握这些能力,并不简单。关于如何学习,做程序员这一行什么工作强度大家都懂,但是不管工作多忙,每周也要雷打不动的抽出 2 小时用来学习。
不出半年,你就能看出变化!
《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》,点击传送门,即可免费领取!
-1711299555512)]
Java语言与原理;
大厂,小厂。Android面试先看你熟不熟悉Java语言
[外链图片转存中…(img-khlbDduT-1711299555512)]
高级UI与自定义view;
自定义view,Android开发的基本功。
[外链图片转存中…(img-zj3lcZ50-1711299555512)]
性能调优;
数据结构算法,设计模式。都是这里面的关键基础和重点需要熟练的。
[外链图片转存中…(img-xth07TuT-1711299555513)]
NDK开发;
未来的方向,高薪必会。
[外链图片转存中…(img-eWSJZsPN-1711299555513)]
前沿技术;
组件化,热升级,热修复,框架设计
[外链图片转存中…(img-iZ0EY6YV-1711299555513)]
网上学习 Android的资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。希望这份系统化的技术体系对大家有一个方向参考。
我在搭建这些技术框架的时候,还整理了系统的高级进阶教程,会比自己碎片化学习效果强太多,CodeChina上可见;
当然,想要深入学习并掌握这些能力,并不简单。关于如何学习,做程序员这一行什么工作强度大家都懂,但是不管工作多忙,每周也要雷打不动的抽出 2 小时用来学习。
不出半年,你就能看出变化!
《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》,点击传送门,即可免费领取!