大喵爱吃鱼的博客

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

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从新手到进阶
上一篇View体系之四大组件——Activity
下一篇View体系之四大组件——Service详解
想对作者说点什么? 我来说一句

android学习笔记2--BroadcastReceiver

2013年02月18日 173KB 下载

广播对应源码

2017年09月15日 20.01MB 下载

BroadcastReceiver

2015年11月11日 2.29MB 下载

android的广播应用

2013年07月22日 432KB 下载

音乐播放器

2014年11月03日 3.28MB 下载

Android四大组件学习实例

2016年03月22日 46B 下载

spring四大组件

2008年04月15日 179B 下载

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

关闭
关闭