Android应用程序可以从Android系统和其他Android应用程序发送或接收广播消息,类似于发布-订阅设计模式。Android中的每个应用程序都可以对自己感兴趣的广播进行注册,这样该程序就只会接收到自己所关心的广播内容。Android广播机制,本质上它就是一种组件间的通信方式。广播的发送者和接收者事先是不需要知道对方的存在的,这样带来的好处便是,系统的各个组件可以松耦合地组织在一起,这样系统就具有高度的可扩展性,容易与其它系统进行集成。

 

一. 广播

广播分为标准广播和有序广播

标准广播

这是一种完全异步执行的广播,在广播发出之后,所有的广播接收器几乎都会在同一时刻接收到这条广播消息,因此它们之间没有任何先后顺序可言。接收器不能对收到的广播做任何处理,也不能截断广播继续传播。该种类的广播用sendBroadcast发送。

1.发送广播

Intent intent = new Intent("com.czb.broadcast_test.MY_BROADCAST");sendBroadcast(Intent);

 

2.想要接收自己发的广播也很简单:
新建一个BroadcastReceiver,
继承BroadcastReceiver并重写onReceive(Context var1, Intent)
在Manifest里面加表明想接收的广播的值

                                        

然后intent.getAction();就可以接收到广播的值了,intent.getExtra("msg");接收Intent里面存的数据。

有序广播

这是一种同步执行的广播,在广播发出之后,同一时刻只会有一个广播接收器能够收到这条广播消息,当这个广播接收器中的逻辑执行完毕后,广播才会继续传递。所以此时的广播接收器是有先后顺序的,优先级高的广播接收器就可以先收到广播消息,并且前面的广播接收器还可以截断正在传递的广播,这样后面的广播接收器就无法收到广播消息了。
该种类的广播用sendOrderedBroadcast发送。

1.发送有序广播

Intent intent = new Intent("com.czb.broadcast_test.MY_BROADCAST");sendOrderedBroadcast(Intent,null);

2.接收有序广播

1.可以识别BroadcastReceiver的优先级;
2.可以截断广播。
先在Manifest里面加一句来设置优先级

priority 必须是整数,默认是0 , 范围是[-1000, 1000]

                                        

然后在标准广播的接收器改一下就可以接收并截断广播了;
onReceive里面加一句abortBroadcast();就可以截断广播了

粘性广播

粘性广播的特点是Intent会一直保留到广播事件结束,而这种广播也没有所谓的10秒限制,10秒限制是指普通的广播如果onReceive方法执行时间太长,超过10秒的时候系统会将这个广播置为可以被干掉的‘候选人’,一旦系统资源不够的时候,就会干掉这个广播而让它不执行。该广播用sendStickyBroadcast发送。
在Android5.0 & API 21中已经失效,所以不建议使用。

系统广播

例如当系统切换到飞机模式时。系统广播被发送到所有订阅了该事件的应用程序。
广播消息本身被包装在一个Intent对象中,其action字符串标识发生的事件(例如android.intent.action.AIRPLANE_MODE)。意图还可能包括绑定到其额外字段中的附加信息。例如,飞机模式意图包含一个额外的布尔值,指示飞机模式是否打开。

应用内广播(本地广播)

本地广播和其他的广播有些不同,它是使用LocalBroadcastManager来发送广播以及注册广播接收器的。
优点:它发出的广播只会在应用程序的内部传播,不用担心广播被其他应用接收,造成数据泄漏,而广播接收器也只能接收到自己应用发出的广播,不会接收别的应用发来的广播,防止接收垃圾信息。

1.发送广播

LocalBroadcastManager lbm = LoadBroadcastManager.getInstance(this);Intent intent = new Intent("com.czb.broadcast_test.MY_BROADCAST")lbm.sendBroadcast(intent);

2.接收本地广播:

LocalBroadcastManager lbm = LoadBroadcastManager.getInstance(this);...LocalReceiver lr = new LocalReceive();Intentfilter intentfliter = new Intentfliter("com.czb.broadcast_test.MY_BROADCAST");//intentFilter.addAction("com.czb.broadcast_test.MY_BROADCAST");lbm.registerReceiver(lr, intentfliter);//注册本地广播监听器class LocalReceiver extends BroadcastReceiver {        @Override        public void onReceive(Context context, Intent intent) {            Toast.makeText(context, "received local broadcast", Toast.LENGTH_SHORT).show();        }}@Overrideprotected void onDestroy() {        super.onDestroy();//        unregisterReceiver(networkChangeReceiver);        lbm.unregisterReceiver(lr);}
  • LocalBroadcastManager.getInstance()获得实例
  • ~.registerReceiver()注册广播
  • ~.sendBroadcast()发送广播
  • ~.unregisterReceiver()取消广播

注意事项:

  • 本地广播无法通过静态注册来接收
  • 在广播中启动活动需要添加FLAG_ACTIVITY_NEW_TASK的标记
  • 在广播中弹出AlertDialog需要添加TYPE_SYSTEM_ALERT

本地广播接收器的优势:
1.明确知道正在发送的广播不会离开我们的程序,因此不必担心信息泄露;
2.其他程序也没办法给我们的程序发送广播,没有安全隐患;
3.本地广播比一开始说的两种广播(系统全局广播)更加高效。

 

二. 广播接收者

要想接受广播,我们需要在项目中注册广播接收者,而注册的方式有两种。

静态注册

一般为常驻广播,在AndroidManifest.xml里通过标签声明

                        

intent过滤器里指定的是接收器订阅的action。
Android 8.0版本以后,系统不再支持,以下摘自官网的更新日志:

为提高设备性能,系统会限制未在前台运行的应用的某些行为。具体而言:1. 现在,在后台运行的应用对后台服务的访问受到限制。2. 应用无法使用其清单注册的大部分隐式广播(即,并非专门针对此应用的广播)。

动态注册

非常驻广播,在使用时注册,用完及时销毁。

BroadcastReceiver br = new MyBroadcastReceiver();IntentFilter filter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION);    filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED);    this.registerReceiver(br, filter);

记得及时注销,以免内存泄漏。

 @Override    protected void onDestroy() {        super.onDestroy();        unregisterReceiver(receiver);    }

三. 带权限的标准广播

发广播

当调用sendBroadcast(Intent, String)sendOrderedBroadcast(Intent, String, BroadcastReceiver, Handler, int, String, Bundle)时,可以指定权限参数。只有申请了该权限的接收者才能接收广播。

//发广播sendBroadcast(new Intent("com.example.NOTIFY"),              Manifest.permission.SEND_SMS);

要想接收这个广播,那么这个接收的app必须申请该权限

当然我们也可以自定义权限(),这里就不展开说了。

接收广播

同理,如果在注册广播接收器时指定了权限参数(使用registerReceiver(BroadcastReceiver,IntentFilter,String,Handler)或清单文件中的里),则只有在清单文件中使用请求权限的广播发送者才可以将Intent发送给接收者。
比如,在清单文件中声明:

                

或者在注册的时候声明:

IntentFilter filter = new IntentFilter(Intent.ACTION_AIRPLANE_MODE_CHANGED);registerReceiver(receiver, filter, Manifest.permission.SEND_SMS, null );

那么,如果要给它发消息,那广播发送的app就必须得申请获得相应的权限才行:

实践

  • 避免在 BroadcastReceiver#onReceive()中执行耗时操作,如果有耗时工作,应该创建 IntentService 完成,而不应该在 BroadcastReceiver 内创建子线程去做。

    说明:
    由于该方法是在主线程执行,如果执行耗时操作会导致 UI 不流畅。可以使用
    IntentService 、创建 HandlerThread 或者调用Context#registerReceiver(BroadcastReceiver, IntentFilter, String, Handler)方法等方式,在其他Wroker线程执行 onReceive方法。BroadcastReceiver#onReceive()方法耗时超过 10 秒钟,可能会被系统杀死。

    示例

    IntentFilter filter = new IntentFilter();        filter.addAction(LOGIN_SUCCESS);        this.registerReceiver(mBroadcastReceiver, filter);        mBroadcastReceiver = new BroadcastReceiver() {            @Override            public void onReceive(Context context, Intent intent) {                Intent userHomeIntent = new Intent();                userHomeIntent.setClass(this, UseHomeActivity.class);                this.startActivity(userHomeIntent);            }        };

     

  • 避免使用隐式 Intent 广播敏感信息,信息可能被其他注册了对应BroadcastReceiver 的 App 接收。
    说明:
    通过Context#sendBroadcast()发送的隐式广播会被所有感兴趣的receiver接收,恶意应用注册监听该广播的receiver可能会获取到Intent中传递的敏感信息,并进行其他危险操作。如果发送的广播为使用Context#sendOrderedBroadcast()方法发送的有序广播,优先级较高的恶意receiver可能直接丢弃该广播,造成服务不可用,或者向广播结果塞入恶意数据。
    如果广播仅限于应用内,则可以使用LocalBroadcastManager#sendBroadcast()实现,避免敏感信息外泄和Intent 拦截的风险

  • Activity或者Fragment中动态注册BroadCastReceiver时,registerReceiver()unregisterReceiver()要成对出现。
    说明
    如果registerReceiver()unregisterReceiver()不成对出现,则可能导致已经注册的receiver没有在合适的时机注销,导致内存泄漏,占用内存空间,加重 SystemService负担。
    部分华为的机型会对receiver进行资源管控,单个应用注册过多receiver会触发管控模块抛出异常,应用直接崩溃。

  • 广播的action是全局的,所以命名的时候尽量包含app的命名空间,以免无意间和其他app冲突

  • 尽量不要在广播接收者中启动activity,这样用户体验很不好,可以考虑用发送通知的方式来代替。

静态注册和动态注册

两者及其接收广播的区别:

(1)动态注册广播不是常驻型广播,也就是说广播跟随Activity的生命周期。注意在Activity结束前,移除广播接收器。

静态注册是常驻型,也就是说当应用程序关闭后,如果有信息广播来,程序也会被系统调用自动运行。

(2)当广播为有序广播时:优先级高的先接收(不分静态和动态)。同优先级的广播接收器,动态优先于静态

(3)同优先级的同类广播接收器,静态:先扫描的优先于后扫描的,动态:先注册的优先于后注册的。

(4)当广播为默认广播时:无视优先级,动态广播接收器优先于静态广播接收器。同优先级的同类广播接收器,静态:先扫描的优先于后扫描的,动态:先注册的优先于后册的。
 

 

https://www.jianshu.com/p/9eeff057cd52

https://www.jianshu.com/p/fae48283cc1c

https://blog.csdn.net/panhouye/article/details/53588930

https://blog.csdn.net/whdAlive/article/details/80250261

更多相关文章

  1. 13-7-6 android底层与zigbee通信
  2. Android技术沙龙系列之:Android(安卓)广播接收器
  3. android 开发屏蔽home键,返回键
  4. android开机自启动的后台Service的实现
  5. android手记之--广播接收者
  6. android 定义 程序 Scheme 接收特定URI开启Activity
  7. Android接收jsp中动态生成的xml或json数据。
  8. Android基于XMPP Smack Openfire开发IM【三】客户端接收服务器发
  9. Android(安卓)系统广播机制

随机推荐

  1. 我的Android读书笔记——(1)
  2. Android 自定义view组件
  3. ActivityThread
  4. Android(安卓)开机动画客制化
  5. Android NDK学习 Android.mk的制作
  6. Android Graphics专题(1)--- Canvas基础
  7. android是什么?
  8. android开发笔记之 Activity四种加载模式
  9. 通过广播Intent控制Android系统自带的音
  10. android 如何彻底关闭应用