大喵爱吃鱼的博客

编程在于积累,积累在于点滴

View体系之四大组件——Andorid广播
 View体系之四大组件——Andorid广播
在详细进行广播介绍以前,我们需要了解以下几个问题:
(1)什么是广播,广播的作用是什么?
(2)普通广播和有序广播的区别
(3)全局广播和本地广播的区别
(4)静态注册和动态注册的区别
(5)BroadCastReceiver和LocalBroadCastManager的区别
(6)为什么会有LocalBroadCastManager,LocalBroadCastManager是静态注册还是动态注册?
(7)广播适合做耗时操作么?anr的时间是多少?
(8)全局广播的安全性分析
(9)如何发送自定义的有序广播和普通广播

一、广播的简介
        广播,作为Android四大组件之一,在我们日常使用中是很常见的。它最大的特点就是管杀不管埋,也就是说我只管发送广播,至于谁接收,接收了怎么处理,那我不管。因此通常它用来传递消息,尤其是跨进程通信。(这里解释了问题(1))
        这里类比我们平常听得收音机电台广播,播音员会通过一个对应的频道发广播,我们需要将收音机调节到对应的频道就可以听到广播,而播音员并不知道是谁收到了广播,收到广播又做了什么。而像我们这样的收听者可以很多个。这是一种典型的发布——订阅模式,也就是观察者模式。
        正如我们上面提到的,电台广播主要包含了三个元素:播音员发送广播,通过对应频道传播,我们接收广播。而Android的广播机制也包含三部分:发送广播,广播的传递Intent,广播的接收。
从是否可以跨进程上来区分,可分为全局广播和本地广播。其中普通广播,有序广播,Sticky广播都是全局广播
从类型来区分,可分为普通广播,有序广播,本地广播,Sticky广播。

二、全局广播和本地广播的原理
         全局广播:基于Binder机制。
                             首先发送者会创建一个广播,然后通过Binder发送到Activity Manager Service,而AMS根据条件查找符合条件的广播接收者。如果找到了对应的广播接收者,则会将广播发送到广播接收这                                对应的进程的消息循环队列中,然后消息队列拿到广播并执行onReceiver()回调,这样就完成了一次广播的发送和接收
          本地广播(LocalBroadCastManager):Handler消息机制
                              利用Handler消息机制。在收到消息时直接调用onReceiver方法。

 三、广播机制的使用场景
  • 同一应用程序内同一组件内
  • 同一应用程序不同组件
  • 同一应用程序内多个进程之间
  • 不同应用程序之间
  • 接收Android特定的广播             

四、普通广播
      1、特点
            全局广播,所有的应用都可以收到,且广播无法被拦截,广播接收者也没有优先级。
      2、具体使用
             无论是静态注册还是动态注册,都是一个步骤,发送广播,接收广播。动态和静态只是注册的方式不一样。
      3、静态注册广播
            所谓静态注册,指的就是在Manifest文件中注册广播,比如:

          首先自定义一个广播接收者NormalToastBroadCast
package com.sky_wf.demoutils.activity;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
import android.widget.Toast;

/**
* @Date : 2018/3/25
* @Author : WF
* @Description :
*/
public class NormalToastBroadCast extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Log.d("tt","NormalToastBroadCast receiver");
Toast.makeText(context,"已经接收到普通广播1"+intent.getStringExtra("key"),Toast.LENGTH_SHORT).show();
}
}

然后在清单文件中注册这个广播接收器
<receiver android:name=".activity.NormalToastBroadCast"
>
<intent-filter>
<action android:name="HELLO"/>
</intent-filter>
</receiver>

     4、动态注册
          无论是动态还是静态都需要首先实现一个自定义的广播接收器,只是在注册的时候,一个是在清单文件,一个在代码里。这里接收器我们就不赘述了,直接看注册:
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction("HELLO");
NormalToastBroadCast4 normalToastBroadCast4 = new NormalToastBroadCast4();
registerReceiver(normalToastBroadCast4,intentFilter);
而实现广播类前面已经介绍了。
       5、发送普通广播
                
Intent intent = new Intent();
intent.setAction("HELLO");
intent.putExtra("key","ok");
sendBroadcast(intent);

发送普通广播需要通过intent来指定广播的Action,然后调用sendBroadCast(intent)来发送
        6、发送有序广播

Intent intent = new Intent();
intent.setAction("HELLO");
intent.putExtra("key","ok");
sendOrderBroadcast(intent);

7、静态广播和动态广播的区别
(1)是否可控。动态广播可以通过registerReceiver和unRegisterReceiver来注册和取消注册广播,而静态广播,在应用第一次启动后就会注册广播,之后一直有效,无法取消注册
(2)资源消耗上。动态广播可控,因此可以及时取消注册,节省资源,但是静态广播无法取消。
(3)有效期。动态广播不是常驻型广播,在取消注册或者是创建接收者的Context被销毁后也就是失效了。但是静态广播是常驻型广播,除非应用删除,否则一直都在。
(4)通常会优先响应动态注册的广播接收器,而处理完后再处理静态的广播接收器。而在静态的广播接收器的响应过程中,多个app都有这个静态的广播接收器,那么响应顺序则与app安装顺序一致(系统app优先)。
8、关于Android 3.1之后静态注册广播的问题
        在Android 3.1以前,静态注册的广播接收器是一直可以接收到广播的,不论它的进程当前是否在运行。而在Android 3.1以后,在系统发送的广播在Intent中添加参数flag
FLAG_INCLUDE_STOPPED_PACKAGES:包含已经停止的包(停止:即包所在的进程已经退出)
FLAG_EXCLUDE_STOPPED_PACKAGES:不包含已经停止的包
而如果进程已经退出,即使有静态注册的广播接收器,也无法接收。当然这是针对系统广播,我们自己的广播,可以覆写这个flag为FLAG_EXCLUDE_STOPPED_PACKAGES,这样就可以接收了。
 
 四、有序广播
        1、特点
             全局广播,而接收广播的先后则是根据广播接收者的优先级来决定的,如果是相同的优先级,那么接受的顺序是随机的。此外,接收者可以消耗掉这个广播(abortBroadCast()),也可以将自己的处理结果传给后面的广播接收者。通过setResultExtra()和getResultExtra()
            优先级的设定可以通过在manifest中的priority属性
        2、具体使用:(基本类似于普通广播的静态注册情形)
                (1)在manifest中声明

<receiver android:name=".activity.OrderToastBroadCast"
android:process=":remote">
<intent-filter
android:priority="1000">
<action android:name="Love"/>
</intent-filter>
</receiver>
<receiver android:name=".activity.OrderToastBroadCast1"
android:process=":remote">
<intent-filter
android:priority="500">
<action android:name="Love"/>
</intent-filter>
</receiver>
<receiver android:name=".activity.OrderToastBroadCast2"
android:process=":remote">
<intent-filter
android:priority="-1000">
<action android:name="Love"/>
</intent-filter>
</receiver>

               (2)实现广播接收者。

package com.sky_wf.demoutils.activity;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.widget.Toast;

/**
* @Date : 2018/3/25
* @Author : WF
* @Description :
*/
public class OrderToastBroadCast extends BroadcastReceiver
{
@Override
public void onReceive(Context context, Intent intent)
{
Log.d("tt","orderToastBroadCast receiver");
Toast.makeText(context, "已经接收到有序广播" + intent.getStringExtra("key"), Toast.LENGTH_SHORT)
.show();
// abortBroadcast();
Bundle bundle = new Bundle();
bundle.putString("name","OrderToastBroadCast");
setResultExtras(bundle);

}
}


package com.sky_wf.demoutils.activity;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.widget.Toast;

/**
* @Date : 2018/3/25
* @Author : WF
* @Description :
*/
public class OrderToastBroadCast1 extends BroadcastReceiver
{
@Override
public void onReceive(Context context, Intent intent)
{
Log.d("tt","orderToastBroadCast1 receiver");
Toast.makeText(context, "已经接收到有序广播" + intent.getStringExtra("key"), Toast.LENGTH_SHORT)
.show();
Bundle bundle=getResultExtras(true);
// Bundle bundle = intent.getExtras();
String s = bundle.getString("name","null");
Log.d("tt","getResultData"+s);
abortBroadcast();

}
}



                (3)发送有序广播

sendOrderedBroadcast(new Intent("Love"),null);

五、本地广播
         类似于普通广播,但是只能在应用内部。和本质上是通过Handler消息机制来实现的
         在使用时,需要使用LocalBroadCastManager来进行动态注册和取消注册,无法使用静态注册。
            (1)注册广播接收者
        
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction("HELLO");
NormalToastBroadCast4 normalToastBroadCast4 = new NormalToastBroadCast4();
LocalBroadcastManager.getInstance(this).registerReceiver(normalToastBroadCast4,intentFilter);
            (2)发送广播
                
LocalBroadcastManager.getInstance(this).sendBroadcast(intent);

六、Sticky广播(粘性广播)
        特点:
         只保留最后一条广播,并且会一直保留这个广播,即使已经有接收者接收了广播,只要新的广播接收注册后,仍然可以接收到该广播。(也就说,发送一次后,广播一直滞留,而不是像其他广播一样,发送一次,然后才可以接收,这里只要发送一次后,不需要再发送,就可以一直接收。)
        使用时需要权限:
    
<uses-permission android:name="android.permission.BROADCAST_STICKY"/>
注意:在Android5.0以后,sticky广播过期,不再建议使用。

七、一些改动
        在android3.1以后,一个应用安装后默认是stoped状态,不能自启动,因此需要启动一次来完成静态广播的注册后才可以接收广播。
       
八、全局广播存在的问题:
        主要的问题也就是来自于跨进程这个问题:
        1、其他app可以发送符合intent-filter的广播,这样应用会一直收到广播
        2、其他app可以注册intent-filter的广播接收器,从而接收到应用的广播内容

八、关于广播耗时和anr的问题:
        广播的生命周期在执行onReceiver()方法后就已经结束了,因此通常不建议在广播中执行异步操作,因为有可能异步还未完成,而广播已经结束导致异步失败,同时默认情况广播运行在UI线程,因此,尽量不要在广播中执行耗时任务。如果10s无响应,那么就会出现anr。
        常见的ANR如下:
         按键,触摸事件在个规定的时间内无响应(5s)
       广播在特定的时间内无发处理完成(10s) 
       Service在规定的时间内无法处理完成(20s)


阅读更多
版权声明:本文为博主原创文章,转载请说明出处 https://blog.csdn.net/ckq5254/article/details/79951447
所属专栏: Android从新手到进阶
想对作者说点什么? 我来说一句

android学习笔记2--BroadcastReceiver

2013年02月18日 173KB 下载

广播对应源码

2017年09月15日 20.01MB 下载

BroadcastReceiver

2015年11月11日 2.29MB 下载

没有更多推荐了,返回首页

不良信息举报

View体系之四大组件——Andorid广播

最多只允许输入30个字

加入CSDN,享受更精准的内容推荐,与500万程序员共同成长!
关闭
关闭