LeoYan Blog

技术分享,生活记录。

0%

Android 之 BroadcastReceiver (一) 相关知识

转载请注明出处:www.leoyanblog.com

本文出自 LeoYan 的博客

本文同步发表于我的微信公众号,扫一扫文章底部的二维码或在微信搜索 LeoYan 即可关注。

BroadcastReceiver 是什么

  BroadcastReceiver 是 Android 四大组件之一,本质是一种全局的监听器,用于监听系统或者应用全局的广播消息,然后根据广播信息做出相应的逻辑处理,也可以用来传输少量、频率低的数据。 因此它可以非常方便的实现不同组件之间的通信。

BroadcastReceiver 的生命周期

  由于 BroadcastReceiver 本质上属于一个监听器,因此实现 BroadcastReceiver 的方法也十分简单,每次系统 Broadcast 事件发生后,系统就会创建对应的 BroadcastReceiver 的实例,并且自动触发他的 onReceive() 方法,onReceive() 方法执行完后,BroadcastReceiver 的实例就会被销毁。也就是说 BroadcastReceiver 的生命周期就是 onReceive() 这个方法。

  如果 BroadcastReceiver 的 onReceive() 方法不能在10秒内执行完成,Android 会认为该程序无响应。所以不要在 BroadcastReceiver 的 onReceive() 方法中执行一些耗时操作,否则会弹出 ANR 的对话框。若必须要执行比较耗时的操作,则要考虑由当前 BroadcastReceiver 启动新的 Service 来完成操作。但不能绑定 Service。

  如果我们在 Activity 中注册了 BroadcastReceiver,当这个 Activity 销毁的时候要主动撤销注册否则会出现异常。

BroadcastReceiver 的创建

  首先,我们来演示一下创建一个 BroadcastReceiver,并让这个 BroadcastReceiver 能够根据我们的需要来运行。

  要创建自己的 BroadcastReceiver 对象,我们需要继承 android.content.BroadcastReceiver,并实现其 onReceive 方法。下面我们就创建一个名为 MyReceiver 广播接收者:

1
2
3
4
5
6
7
8
9
10
11
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 注册广播地址。

BroadcastReceiver的注册

  BroadcastReceiver 的注册方式有且只有两种,一种是静态注册(推荐使用),另外一种是动态注册,广播接收者在注册后就开始监听系统或者应用之间发送的广播消息。

静态注册

  静态注册是在 AndroidManifest.xml 文件中配置的,在 application 里面定义 receiver 并设置要接收的 action。我们就来为 MyBroadcastReceiver 注册一个广播地址:

1
2
3
4
5
6
<receiver android:name=".MyBroadcastReceiver">  
<intent-filter android:priority = "777">
<action android:name="android.intent.action.MY_BROADCAST"/>
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</receiver>

  这里的 priority 取值是 -1000 到 1000,值越大优先级越高。配置了以上信息之后,只要是 android.intent.action.MY_BROADCAST 这个地址的广播,MyBroadcastReceiver 都能够接收的到。

  要销毁掉静态注册的广播接收者,可以通过调用 PackageManager 将 Receiver 禁用。

动态注册

  动态注册需要在代码中动态的指定广播地址并注册,通常我们是在 Activity 或 Service 中声明 BroadcastReceiver 的扩展对象,在 onResume 中注册,onPause 中卸载。下面我们就来看一下注册的代码:    

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class MainActivity extends Activity {

MyBroadcastReceiver receiver;

@Override
protected void onResume() {
// 动态注册广播 (代码执行到这才会开始监听广播消息,并对广播消息作为相应的处理)
receiver = new MyBroadcastReceiver();
IntentFilter intentFilter = new IntentFilter( "android.provider.Telephony.SMS_RECEIVED" );
registerReceiver( receiver , intentFilter);

super.onResume();
}

@Override
protected void onPause() {
// 撤销注册 (撤销注册后广播接收者将不会再监听系统的广播消息)
unregisterReceiver(receiver);
super.onPause();
}
}

注意,当这个 Activity 或 Service 被销毁时如果没有解除注册,系统会报一个异常,提示我们是否忘记解除注册了。所以,记得在特定的地方执行解除注册操作。

静态注册和动态注册的区别

  • 区别 1

  静态注册的广播接收者是一个常驻在系统中的全局监听器,也就是说无论应用是否处于运行状态,如果有广播信息传来,MyBroadcastReceiver 也会被系统调用而自动运行。

  动态注册方式与静态注册相反,不是常驻型的,也就是说广播会跟随程序的生命周期。

  • 区别 2

  当广播接收者通过 Intent 启动一个 Activity 或者 Service 时,如果 Intent 中无法匹配到相应的组件。动态注册的广播接收者将会导致应用报错。而静态注册的广播接收者将不会有任何报错,因为自从应用安装完成后,广播接收者跟应用已经脱离了关系。 

Broadcast 的类型

  发送广播主要有两种类型:

普通广播

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

有序广播

  有序广播比较特殊,它每次只发送到优先级较高的接收者那里,然后由优先级高的接收者将处理好的数据再传播到优先级低的接收者那里,优先级高的接收者有能力调用 abortBroadcast() 来终止这个广播。

  同级别接收是先后是随机的,如果先接收到的把广播截断了,同级别的例外的接收者是无法收到该广播。

1
2
// 发送有序广播
sendOrderedBroadcast(intent, null);

  演示有序广播的流程,如下:

1
2
3
4
5
6
7
8
9
10
public void onReceive(Context arg0, Intent intent) {
  //获取上一个广播的bundle数据
  Bundle bundle = getResultExtras(true);//true:前一个广播没有结果时创建新的Bundle;false:不创建Bundle
  bundle.putString("key", "777");
  //将bundle数据放入广播中传给下一个广播接收者
  setResultExtras(bundle); 
  
  //终止广播传给下一个广播接收者
  abortBroadcast();
}

总结

  • 静态广播接收的处理器是由 PackageManagerService 负责,当手机启动或者新安装了应用的时候,PackageManagerService 会扫描手机中所有已安装的APP应用,将 AndroidManifest.xml 中有关注册广播的信息解析出来,存储至一个全局静态变量当中。

  • 动态广播接收的处理器是由 ActivityManagerService 负责,当 APP 的服务或者进程起来之后,执行了注册广播接收的代码逻辑,即进行加载,最后会存储在一个另外的全局静态变量中。需要注意的是:

  1、这个并非是一成不变的,当程序被杀死之后,已注册的动态广播接收器也会被移出全局变量,直到下次程序启动,再进行动态广播的注册,当然这里面的顺序也已经变更了一次。

  2、这里也并没完整的进行广播的排序,只记录注册的先后顺序,并未有结合优先级的处理。

  • 广播发出的时候,广播接收者的接收顺序如下:

  1、当广播为 普通广播 时,有如下的接收顺序:

    无视优先级

    动态优先于静态

    同优先级的动态广播接收器,先注册的大于后注册的

    同优先级的静态广播接收器,先扫描的大于后扫描的 

  2、当广播为 有序广播,那么会将动态广播处理器和静态广播处理器合并在一起处理广播的消息,最终确定广播接收的顺序: 

    优先级高的先接收

    同优先级的动静态广播接收器,动态优先于静态

    同优先级的动态广播接收器,先注册的大于后注册的

    同优先级的静态广播接收器,先扫描的大于后扫描的