View体系之四大组件——BroadCastReceiver

版权声明:本文为博主原创文章,转载请说明出处 https://blog.csdn.net/ckq5254/article/details/79951447

                  View体系之四大组件——BroadCastReceiver

题记:

其实很早以前就已经总结过广播,工作中也遇到过广播,但是没有做过详细的总结,直到前天,有人问我,你直到常见的哪些是系统广播?哪些是有序广播?哪些是全局广播么?为什么使用LocalBroadCast?一时间竟然回答不上来,所以这次就做一个详细的总结,作为参考,时间戳:2018/0803

一、广播的简介

二、全局广播和应用内广播

三、普通广播

1、特点

2、具体使用

3、静态注册

4、动态注册

5、发送普通广播

6、发送有序广播

四、有序广播

1、特点

2、具体使用

五、系统广播

六、Sticky广播

七、应用内广播

1、特点

2、使用场景

3、具体使用

八、静态注册和动态注册对比

九、广播的ANR问题

一、广播的简介

        广播,作为Android四大组件之一,在我们日常使用中是很常见的。通常我们会使用它来进行应用之间或者应用内的信息传递,因此它也是常见的IPC通信的方式之一。

 那么到底什么是广播,在上个世纪的时候,广播是神流行的,通常呢由电台发出,然后我们通过收音机来收听,只有在电台发出,并且听众打开收音机并且调频到对应频道才能接收到。而Android中的广播也是一样,这里的电台就是广播的发出者,可以是应用发出或者是系统发出,而其他需要接收广播的应用就是听众   ,应用注册广播接收器就是调频接收的过程,这样比喻应该很好理解吧。

Android中的广播,我们大体可以分为五类:

  • 普通广播(Normal BroadCast)
  • 有序广播(Orderd BroadCast)
  • 系统广播(System BroadCast)
  • 粘性广播(Sticky BroadCast)
  • APP应用内广播(Local BroadCast)

 

二、全局广播和应用内广播

按照是否是跨进程,Andorid中的广播又可以分为全局广播和应用内广播。

其中普通、有序、系统、Sticky都属于全局广播。

全局广播是基于Binder机制来进行跨进程通信,在应用注册广播接收器后,实际上是在AMS中注册;在广播发出后会通过Binder发送到AMS,之后AMS查找符合条件的广播接收者,如果找到就将广播发送到对应进程的消息队列中,之后调用广播的onReceiver()中。

应用内广播是基于主线程的Looper新建了一个Handler,handleMessage()会调用接收器对广播的消息进行处理。

 

 

三、普通广播

1、特点

            是全局广播,所有的应用都可以收到,且广播无法被拦截,广播接收者也没有优先级。可以静态注册也可以动态注册。

 2、具体使用

            无论是静态注册还是动态注册,都是一个步骤,发送广播,接收广播。动态和静态只是注册的方式不一样。

 3、静态注册

            所谓静态注册,指的就是在Manifest文件中注册广播,比如:

          首先自定义一个广播接收者NormalToastBroadCast

package com.sky_wf.demoutils.activity;



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");

sendBroadcast(intent);

 

  6、发送有序广播

Intent intent = new Intent();

intent.setAction("HELLO");

intent.putExtra("key","ok");

sendOrderBroadcast(intent);

       

 四、有序广播

        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)实现广播接收者。

/**

* @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);



}

}





/**

* @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);

 

五、系统广播

Andoid中内置了多个系统广播,例如常见的开机、网络状态变化、拍照等,而系统广播都属于全局广播。

常见的系统广播如下:

系统操作

action

监听网络变化

android.net.conn.CONNECTIVITY_CHANGE

关闭或打开飞行模式

Intent.ACTION_AIRPLANE_MODE_CHANGED

充电时或电量发生变化

Intent.ACTION_BATTERY_CHANGED

电池电量低

Intent.ACTION_BATTERY_LOW

电池电量充足(即从电量低变化到饱满时会发出广播

Intent.ACTION_BATTERY_OKAY

系统启动完成后(仅广播一次)

Intent.ACTION_BOOT_COMPLETED

按下照相时的拍照按键(硬件按键)时

Intent.ACTION_CAMERA_BUTTON

屏幕锁屏

Intent.ACTION_CLOSE_SYSTEM_DIALOGS

设备当前设置被改变时(界面语言、设备方向等)

Intent.ACTION_CONFIGURATION_CHANGED

插入耳机时

Intent.ACTION_HEADSET_PLUG

未正确移除SD卡但已取出来时(正确移除方法:设置–SD卡和设备内存–卸载SD卡)

Intent.ACTION_MEDIA_BAD_REMOVAL

插入外部储存装置(如SD卡)

Intent.ACTION_MEDIA_CHECKING

成功安装APK

Intent.ACTION_PACKAGE_ADDED

成功删除APK

Intent.ACTION_PACKAGE_REMOVED

重启设备

Intent.ACTION_REBOOT

屏幕被关闭

Intent.ACTION_SCREEN_OFF

屏幕被打开

Intent.ACTION_SCREEN_ON

关闭系统时

Intent.ACTION_SHUTDOWN

重启设备

Intent.ACTION_REBOOT

 

六、Sticky广播

在Android5.0中已经失效,不建议使用,这里我也懒得总结了。

七、应用内广播

1、特点

只能在应用内传递信息的广播,不能跨进程,原理上和全局广播不同,这里是利用在主线程中创建了Hanler,用于处理消息。

2、使用场景

需要发送广播并且在接收广播时做出处理

由于全局广播中,如果其他app发出与app中intent-filter相匹配的广播时,该app会不断接收到广播

如果其他app注册与当前app一致的intent-filter用于接收广播,会获取广播内容。

这两种场景下会出现安全性和效率性的问题

3、具体使用

需要使用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);

 

 

八、静态注册和动态注册对比

(1)是否可控。动态广播可以通过registerReceiver和unRegisterReceiver来注册和取消注册广播,而静态广播,在应用第一次启动后就会注册广播,之后一直有效,无法取消注册

(2)资源消耗上。动态广播可控,因此可以及时取消注册,节省资源,但是静态广播无法取消。

(3)有效期。动态广播不是常驻型广播,在取消注册或者是创建接收者的Context被销毁后也就是失效了。但是静态广播是常驻型广播,除非应用删除,否则一直都在。

(4)通常会优先响应动态注册的广播接收器,而处理完后再处理静态的广播接收器。而在静态的广播接收器的响应过程中,多个app都有这个静态的广播接收器,那么响应顺序则与app安装顺序一致(系统app优先)。

注意:

在Android 3.1以前,静态注册的广播接收器是一直可以接收到广播的,不论它的进程当前是否在运行。而在Android 3.1以后,在系统发送的广播在Intent中添加参数flag

FLAG_INCLUDE_STOPPED_PACKAGES:包含已经停止的包(停止:即包所在的进程已经退出)

FLAG_EXCLUDE_STOPPED_PACKAGES:不包含已经停止的包

而如果进程已经退出,即使有静态注册的广播接收器,也无法接收。当然这是针对系统广播,我们自己的广播,可以覆写这个flag为FLAG_EXCLUDE_STOPPED_PACKAGES,这样就可以接收了。

此外, 在android3.1以后,一个应用安装后默认是stoped状态,不能自启动,因此需要启动一次来完成静态广播的注册后才可以接收广播。

 

九、广播的ANR问题

广播的onRecuiver方法是在UI线程的,因此不要在onReceiver()中执行耗时任务,而在执行异步任务时,有可能出现异步任务还未执行完广播就已经结束。

广播在10s内没有处理完会发生过ANR.

 

 

 

 

阅读更多
想对作者说点什么? 我来说一句

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