天天看点

Android四大组件之BroadcastReceiver知多少1、定义说明。2、使用场景。 3、内部机制(原理)。4、使用介绍。         5、注意事项。

说明:BroadcastReceiver——广播接收者,是Android四大组件之一,在实际的开发过程中BroadcastReceiver的应用场景非常多,本篇文章将详细讲解一下BroadcastReceiver,如果各位码友发现文中说明存在问题欢迎指正,CV操作请注明出处,谢谢!

1、定义说明。

    BroadcastReceiver即广播接收者,是Android四大组件之一,是一个全局的监听器。在Android中广播分为广播发送者和广播接收者,广播发送者(一般是其他的组件进行sendBroadcast操作),广播接收者(BroadcastReceiver)对发送出来Broadcast进行过滤、接收和响应。

2、使用场景。

    Android不同组件间的通信(包括进程内和进程之间,同一App和不同App)。

    与Android系统通信(如开机、网络状态、安装/卸载应用等)。

3、内部机制(原理)。

    设计模式:采用了观察者模式,基于消息的发布/订阅事件模型,使得广播的发送者和广播的接收者进行解耦。

    参与角色:广播(消息)发送者、广播(消息)接收者、AMS(ActivityManagerService)

    实现步骤概况:

    1、广播接收者通过Binder机制在AMS注册。

    2、广播发送者通过Binder机制在AMS发送广播。

    3、AMS根据广播发送者的要求,在注册列表中,根据IntentFilter /Permission查找目标广播接受者。

    4、AMS将广播发送给目标广播接收者的消息队列中。

    5、广播接收者通过消息队列获取消息,然后回调onReceive()。

4、使用介绍。

    4.1、广播的接收。

    广播接收者的使用大概分为三步:创建广播接收者、注册广播接收者、根据需求实现逻辑。

    4.1.1 、创建广播接收者。继承BroadcastReceivre,复写抽象方法onReceive()。

    public class XxxReceiver extends BroadcastReceiver {

        private static final String TAG = "XxxReceiver";

        public XxxReceiver() {

        }

        @Override

        public void onReceive(Context context, Intent intent) {

        //处理业务逻辑等,如发送Notification、启动Service等

        }

    }

    注意:onReceive运行在UI线程中,因此,onReceive()方法不能执行耗时操作,否则将导致ANR

    另外不要在此有开启子线程的操作,会造成内存泄漏,如果需要请采用其他方式或者IntentService。

    4.1.2 、注册广播接收者(Android 8.0大部分静态注册广播失效,仅剩下较少的系统广播可以静态注册)。

     1、静态注册,即在清单文件中为BroadcastReceiver进行注册,使用<receive >标签声明,并在标签内<intent-filter >标签设置过滤器。

     这种形式的 BroadcastReceiver 的生命周期伴随着整个应用,如果这种方式处理的是系统广播,那么不管应用是否在运行,该广播接收器都能接收到该广播

     <receiver android:name=".XxxReceiver">

            <intent-filter>

                <action android:name="com.example.leisure.yyy" />

                <!--过滤属性,只有具有该属性的广播才会被接收-->

            </intent-filter>

        </receiver>

     <XxxReceiver 

        广播接收者为四大组件之一,也具有下边的较为常用的属性

         android:exported="true"<!--外部应用是否可以调用,默认为true,如果不对外开放,建议false-->

         android:permission=""<!--具有相应权限的广播发送者发送的广播才能被此BroadcastReceiver所接收-->

         android:process=""<!--指定进程-->

         android:enabled=""<!--能否接收其他App的发出的广播-->

     2、动态注册。即在代码中定义并设置好一个IntentFilter对象,然后在需要注册的地方调用Context.registerReceiver()方法,调用Context.unregisterReceiver()可以取消注册。

        @Override

        public void onCreate() {

            super.onCreate();//注册广播

            IntentFilter intentFilter = new IntentFilter();

            intentFilter.addAction("com.example.leisure.yyy");//

            receiver = new XxxReceiver();

            registerReceiver(receiver, intentFilter);

        }

        @Override

        public void onDestroy() {

            super.onDestroy();//取消注册广播

            unregisterReceiver(receiver);

        }

        注意:动态广播的注册和取消注册须要成对出现。如果Activity/Fragment中建议在onResume()注册、onPause()注销广播因为onPause()在App死亡前一定会被执行,从而保证广播在App死亡前一定会被注销,从而防止内存泄露。除非必要不建议在onCreate()/onDestory() 或 onStart()/onStop()注册、注销,因为当系统因为内存不足(如优先级更高的应用需要内存)要回收Activity占用的资源时,Activity在执行完onPause()方法后就会被销毁,有些生命周期方法onStop(),onDestory()就不会执行。

当再回到此Activity时,是从onCreate方法开始执行,造成内存泄漏。

4.2、广播的发送。

4.2.1、广播的分类,可分为5种:Normal Broadcast、System Broadcast、Sticky Broadcast、Local Broadcast。

        1、普通广播(Normal Broadcast)。

        最为常用的广播,一般需要添加action,声明了对应的action的广播接收者才能收到广播,即onReceive()回调。如果添加了权限,则广播接收者也需要在注册的时候明确权限。

        Intent intent = new Intent();

        //对应BroadcastReceiver中intentFilter的action,

        intent.setAction("com.example.leisure.yyy");

        //发送广播

        sendBroadcast(intent);

        2、系统广播(System Broadcast)。

        系统广播,不需要app去发送,由系统根据情况自动发送,app只负责接收(如果需要)。

        3、有序广播(Ordered Broadcast)。发送出去的广播被广播接收者按照先后顺序接收,有序是针对广播接收者而言的。

         广播接受者接收的顺序规则是按照Priority属性值从大到小排序(同一Priority,动态注册的广播优先级大于静态注册的广播);

         先接收的广播接收者可以对广播进行拦截,小优先级的广播接收者将无法收到该广播;

         先接收的广播接收者可以对广播进行修改,小优先级的广播接收者将接收到被修改后的广播。

        示例:

        Intent intent = new Intent("com.receiver.leisure.common");

        intent.putExtra("xxx", "有序广播");

        sendOrderedBroadcast(intent, null);//发送有序广播

        //此处忽略了注册过程。

        public class OrderReceiverXxx extends BroadcastReceiver {//第一优先级

            public OrderReceiverXxx() {

            }

            @Override

            public void onReceive(Context context, Intent intent) {

                //取出Intent当中传递来的数据

                String msg = intent.getStringExtra("xxx");

                //向下一优先级的Receiver传递数据

                Bundle bundle = new Bundle();

                bundle.putString("yyy", "xxx修改了广播");

                setResultExtras(bundle);

            }

        }

        public class OrderReceiverYyy extends BroadcastReceiver {//第二优先级

            public OrderReceiverYyy() {

            }

            @Override

            public void onReceive(Context context, Intent intent) {

                //取出上一优先级的Receiver传递来的数据

                String data = getResultExtras(true).getString("yyy");

                //拦截广播

                abortBroadcast();

            }

        }

        public class OrderReceiverZzz extends BroadcastReceiver {//第三优先级

            public OrderReceiverZzz() {

            }

            @Override

            public void onReceive(Context context, Intent intent) {

                //收不到广播了

            }

        }

        4、粘性广播(Sticky Broadcast)。Android5.0(API 21)中已经失效,可忽略。

        5、本地广播(Local Broadcast)。

    由于Android中的广播可以跨进程(App)通信,不同的App注册的广播intent-filter可能会相同,也存在其他App根据intent-filter针对性的恶意发送某些广播造成安全或者效率问题。

    Android内提供了本地广播,广播的发送者和接收者都同属于一个App,提高了效率和安全性。

    针对普通广播效率和安全性的问题,一般有两种方式:

        1、注册广播时候将exported属性设置为false;增设相应权限permission,用于权限验证;发送广播指定包名。

        2、建议使用本地广播的形式。

        本地广播是使用LocalBroadcastManager来对广播进行管理,和普通广播存在注册、发送的方式的细微差别,除此之外都一样。

        LocalBroadcastManager.getInstance(this).registerReceiver(BroadcastReceiver, IntentFilter)

        注册Receiver

        LocalBroadcastManager.getInstance(this).unregisterReceiver(BroadcastReceiver);

        注销Receiver

        LocalBroadcastManager.getInstance(this).sendBroadcast(Intent)

        发送异步广播

        LocalBroadcastManager.getInstance(this).sendBroadcastSync(Intent)

        发送同步广播

5、注意事项。

1、不同注册方式的广播接收器回调OnReceive(Context context,Intent intent)中的context返回值是不一样的,静态注册的广播是ReceiverRestrictedContext;动态注册的广播是Activity Context;本地广播是Application Context。

继续阅读