当前位置:   article > 正文

Android广播接收器精炼详解—你所需要知道的广播_安卓中广播接收器的概念与分类

安卓中广播接收器的概念与分类
一、前期基础知识储备

(1)什么是广播

广播在日常生活中就是用来通知一些消息,而Android系统为了方便一些消息的通知,也产生了广播的机制。

Android的广播机制比较灵活,每一个应用程序都可以对自己感兴趣的广播进行注册,这样就只能收到自己想听的广播;这些广播可能来自于系统,也可能来自于其他应用程序。(来短信会产生广播、wifi变化也会产生广播...)

广播可以实现不同app之间的通信,也可以实现同一app内不同组件的通信,Android提供一套API来方便我们使用广播。

(2)如何接收广播?

要接收广播就必须引入一个新的概念,广播接收者,它是专门负责接收Android广播的。定义一个广播接收者,需要一个类继承自BroadcastReceiver,实现onReceiver()方法。onReceive(Context context,Intent intent) 就只有这一个方法:

①context 上下文 ②intent携带其他Activity的信息,即为广播的详细内容。

(3)广播背后的机制详解

①广播接收者BroadcastReceiver通过Binder机制向AMS(ActivityManager Service)进行注册;

②广播发送者通过Binder机制向AMS发送广播;

③AMS查找符合相应条件(IntentFilter/Permission等)的BroadcastReceiver,将广播发送到BroadcastReceiver(一般情况下是Activity)相应的消息队列中;

④消息循环执行拿到此广播,回调BroadcastReceiver中的onReceiver()方法。由此看来,广播发送者和广播接收者分别属于观察者模式中的消息发布和订阅的两端,AMS属于中间的处理中心。广播发送者和广播接收者的执行是异步的,发出去我的广播不会关心有无接收者接收,也不确定接收者是何时才能接收到。实现完全的解耦合

二、上代码,具体实现一次接收系统广播

接收一个系统广播,分四步走:创建广播——注册广播——发送广播——运行代码

(1)创建广播接收者

  1. public class MyBroadcastReceiver extends BroadcastReceiver {
  2. @Override
  3. public void onReceive(Context context, Intent intent) {
  4. //对接收到的广播进行处理,intent里面包含数据
  5. }
  6. }

(2)注册广播—静态注册/动态注册

静态注册广播接收者

静态注册是在AndroidManifest.xml文件中配置的。

  1. <receiver android:name="com.hua.bcreceiver.MyBroadcastReceiver" >
  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>

动态注册广播接收者

动态注册需要在Java代码中动态的指定广播地址并注册

  1. //创建广播
  2. MyBroadcastReceiver mbcr = new MyBroadcastReceiver();
  3. IntentFilter filter = new IntentFilter();
  4. filter.addAction(MyBroadcastReceiver.MY_BC_FIRST);
  5. //注册广播
  6. registerReceiver(mbcr, filter);

注,registerReceiver是android.content.ContextWrapper类中的方法,Activity 和Service都继承了ContextWrapper,所以可以直接调用。 在实际应用中,我们在 Activity或Service中注册了一个BroadcastReceiver,当这个Activity或Service被销毁时 如果没有解除注册,系统会报一个异常,提示我们是否忘记解除注册了。所以,记得动态注册广播之后,记得取消注册

  1. @Override
  2. protected void onDestroy() {
  3. unregisterReceiver(mbcr);
  4. mbcr = null;
  5. super.onDestroy();
  6. }

通过上面两步其实已经完成了一个简单功能的广播接收者,已经可以具有接受广播功能了。在onReceive()方法里面就可以做自己想要的处理。

————————————————————我是分隔线————————————————————

(3)静态注册和动态注册的区别

静态注册的广播的程序运行一次后,以后能一直保持广播接收的状态,只要有对应的广播就能接收它的广播信息。

优点:程序不启动,一样能收到广播,一般用于推送(自己搭建)。系统的处理。

缺点:占用资源较多。只有广播,系统会去匹配所有的接受者。

动态注册的广播需要程序在运行中才能接收广播。

优点:程序占用资源少,及时释放

缺点:一定需要组件启动,注册广播。

(4)广播的优先级

广播和线程一样都是有优先级的,系统会优先接收优先级更高的广播。

在静态代码块中定义

<intent-filter android:priority="XXX">

使用java动态代码设置

filter.setPriority(XXX);

Priority值越大,代表广播优先级越高,越高优先的广播会被优先接收到。

三、上代码,自定义广播来发送消息

上面我们简单实现了一个接收系统广播的操作,我们在实际开发中,也可以为我们的应用程序设置自己的广播,用于对外部发送消息。下面我们先来看看广播的分类:

(1)标准广播

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

  1. //标准广播启动方式
  2. Intent intent = new Intent(“myBroadcastReceiver”);
  3. intent.putExtra(“msg”, “这是MainActivity页面发送的广播—-》》”);
  4. sendBroadcast(intent);

(2)有序广播

有序广播比较特殊,它每次只发送到优先级较高的接收者那里,然后由优先级高的接受者再传播到优先级低的接收者那里,优先级高的接收者有能力终止这个广播。可以在广播注册时使用intent-filter里面的android: priority=”xxx”去解决或在java代码中用setPriority(xxx)来设置。

  1. //有序广播启动方式
  2. Intent intent = new Intent(“myBroadcastReceiver”);
  3. intent.putExtra(“msg”, “这是MainActivity页面发送的广播—-》》”);
  4. sendOrderedBroadcast(intent,null);//如果是该自定义的广播接收者发送广播,第二个参数一般为null

有序广播中有以下三种方法,供每个广播进行设置——使用setResult()函数来结果传给下一个广播接收器接收,然后通过getResult()函数来取得上个广播接收器接收返回的结果。setResult()方法也用来修改。当广播接收器接收到广播后,也可以用abortBroadcast()函数来让系统拦截下来该广播,并将该广播丢弃

小结:可以看到,两段代码,没有什么不同,只是启动方式标准广播是sendBroadcast(intent),有序广播是sendOrderedBroadcast(intent,null),但实质上,两种的广播的处理逻辑完全不同。

在实际开发中,会使用有序广播,尽管有弊端,但是可以做到筛选广播

————————————————————我是分隔线————————————————————

开始自定义广播,然后发送广播。这里我们定义三个广播,优先级分别为1000、2000、3000,具体分三步走:

创建广播接收者

  1. public class PriorityBroadcastReceiver {
  2. public static class HighPriority extends BroadcastReceiver {
  3. //高级广播接收者
  4. @Override
  5. public void onReceive(Context context, Intent intent) {
  6. Log.e("receive", "High");
  7. //传递结果到下一个广播接收器
  8. int code = 0;
  9. String data = "hello";
  10. Bundle bundle = null;
  11. setResult(code, data, bundle);
  12. }
  13. }
  14. public static class MidPriority extends BroadcastReceiver {
  15. //中级广播接收者
  16. @Override
  17. public void onReceive(Context context, Intent intent) {
  18. Log.e("receive", "Mid");
  19. //获取上一个广播接收器结果
  20. int code = getResultCode();
  21. String data = getResultData();
  22. Log.e("receive", "获取到上一个广播接收器结果:" + "code=" + code + "data=" + data);
  23. }
  24. }
  25. public static class LowPriority extends BroadcastReceiver {
  26. //低级广播接收者
  27. @Override
  28. public void onReceive(Context context, Intent intent) {
  29. Log.e("receive", "Low");
  30. }
  31. }
  32. }

注:1.   内部类的BroadcastReceiver必须由public static修饰,否则会报错。

注册广播

这里的注册方式和普通广播是一样的,这里的区别在于priority属性,确定了他们之间的优先级。

  1. <receiver android:name=".BroadcastReceiver.PriorityBroadcastReceiver$HighPriority">
  2. <intent-filter android:priority="3000">
  3. <action android:name="com.handsome.hensen2" />
  4. </intent-filter>
  5. </receiver>
  6. <receiver android:name=".BroadcastReceiver.PriorityBroadcastReceiver$MidPriority">
  7. <intent-filter android:priority="2000">
  8. <action android:name="com.handsome.hensen2" />
  9. </intent-filter>
  10. </receiver>
  11. <receiver android:name=".BroadcastReceiver.PriorityBroadcastReceiver$LowPriority">
  12. <intent-filter android:priority="1000">
  13. <action android:name="com.handsome.hensen2" />
  14. </intent-filter>
  15. </receiver>

注:BroadcastReceiver类名与内部类的名字之间用$符号隔开,否则会报错

发送广播

这里是使用sendOrderedBroadcast()发送有序广播

  1. final Intent intent = new Intent();
  2. intent.setAction("com.handsome.hensen2");
  3. bt_send.setOnClickListener(new View.OnClickListener() {
  4. @Override
  5. public void onClick(View v) {
  6. sendOrderedBroadcast(intent,null);
  7. }
  8. });

注:这里需要发送的是有序广播,否则在接收者中通过setResult()和getResult()方法会报错,因为只有有序广播才能传递结果

 

最后提一点:当系统或其他程序发出广播时,Android系统的包管理对象就会检查所有已安装的包的配置文件有没有匹配的action,如果有,并且可以接收,那么就调用这个BroadcastReceiver,获取BroadcastReceiver对象,然后执行onReceive()。BroadcastReceiver是在intent匹配后再实例化的,而且每次都是重新实例化的。(由此可见,广播的生命周期是非常短的—10秒

所以,请不要再广播中执行耗时操作

 


声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/繁依Fanyi0/article/detail/472276
推荐阅读
相关标签
  

闽ICP备14008679号