android全方位解析BroadcastReceiver

来源:互联网 发布:淘宝拍单软件 编辑:程序博客网 时间:2024/06/05 10:54

概念:

作为android的四大组件,相信很多人都知道BroadcastReceiver,那什么是BroadcastReceiver ? 直译是“广播接收者”,作用是接受发送过来的广播。那么是广播,举个例子:当我们上课,如果没有听到下课铃声,就不会出去教室,下课。当下课铃声后,我们就知道下课了,广播可以理解是一种消息的传递。再举个例子:我们开机时,系统会进行一个全局广播,消息是开机启动了,还有网络断开,链接到wifi,电量改变,系统都会作出反应。

Android里面的Broadcast其实跟我们生活中广播的意思很像,主要是用来消息通信(IPC),Android的IPC基本都是binder来实现,而BroadcastReceiver其实是对binder的一个封装,方便上层调用,在平时很多时候都是单进程但线程通信,很多人都会用Observer或者使用EventBus等来完成功能,的确,它们在这场合效率和灵活性都非常高,但是,BroadcastReceiver有自己独有的优势,第一是系统事件的监听,如:开机启动,电量变化;第二多进程通信,如现在多进程保活机制里面就用到了一些系统广播的监听。

原理:

Android中的广播使用了设计模式中的观察模式:基于消息的发布/订阅事件模型,而这个模型有三个角色:1.广播接收者,2:广播发送者,3:消息中心(Activity Manager Service),广播接收者通过Binder机制在AMS注册,广播发送者通过Binder机制向AMS发送广播,AMS根据广播发送者要求,在已注册列表中寻找合适的广播接收者,通过IntentFilter来进行刷选。AMS将广播发送到合适的广播接收者相应的消息循环队列中,广播接收者通过消息循环拿到广播,并回调onReceiver().注意:广播发送者和广播接收者的执行是异步,发出去的广播不会关心有没有接收者接收,也不知道接收者什么时候能接受到。

具体使用:

1.动态注册

步骤:

1.通过继承BroadcastReceiver建立动态广播接收器或者匿名内部类实现

2.实例化IntentFilter对象

3.注册广播接收

4.移除广播接收器优化内存空间避免内存溢出

    BroadcastReceiver mBroadcasrReceive = new BroadcastReceiver() {        @Override        public void onReceive(Context context, Intent intent) {            String action = intent.getAction();            if(action.equals(Constant.LOGIN_SUCCESS)){                text_send.setText("收到动态广播");            }        }    };


        IntentFilter intentFilter = new IntentFilter();        intentFilter.addAction(Constant.LOGIN_SUCCESS);        registerReceiver(mBroadcasrReceive,intentFilter);


    @Override    protected void onPause(){        super.onPause();        unregisterReceiver(mBroadcasrReceive);    }


发送广播:

Intent mintent = new Intent(Constant.LOGIN_SUCCESS);
mintent.putExtra("yanner","发送广播");
//发送广播
sendBroadcast(mintent);


这样动态方式就可以实现。注意:动态广播最好在Activity的onResume()注册,onPause()注销。动态广播,有注册就必然有注销,否则会导致内存泄漏,重复注册和注销都是不允许的。为什么要在onPause()注销呢,因为onPause()在App死亡前一定会被执行,这样保证广播在App死亡前一定会被注销,从而防止内存泄漏。不在onStop()&onDestory()注销因为当系统如果内存不足时要回收Activity占用的资源时,Activity在执行完onPause()方法后就会被销毁,有些生命周期方法onStop(),onDestory()就不会执行。当再回到此Activity时,是从onCreate方法开始执行。所以如果将广播的注销放在onStop(),onDestory()方法里的话,有可能在Activity被销毁后还未执行onStop(),onDestory()方法,广播仍未注销,从而导致内存泄漏。,但是onPause()一定会被执行的。


2.静态注册

步骤:

1.继承BroadcastReceiver,重写onReceive方法

public class StaticReceiver extends BroadcastReceiver {    @Override    public void onReceive(Context context, Intent intent) {        if(intent.getAction().equals(Constant.REGISTER_SUCCESS)){            Toast.makeText(context,"收到静态广播",Toast.LENGTH_SHORT).show();        }    }}


2.在清单文件注册

 <!--继承BroadcastReceiver子类的类名-->        <receiver android:name=".receiver.StaticReceiver">            <intent-filter>                <!--action android:name="com.broadcast.REGISTER_SUCCESS"必须跟发送广播的action一致 -->                <action android:name="com.broadcast.REGISTER_SUCCESS"/>            </intent-filter>        </receiver>

注意这是自定义广播。

也可以使用系统广播:

以接收短信为例:

public class MyBroadcastReceiver extends BroadcastReceiver {    //action 名称    String SMS_RECEIVED = "android.provider.Telephony.SMS_RECEIVED";    @Override    public void onReceive(Context context, Intent intent) {        if(intent.getAction().equals(SMS_RECEIVED)){            //相关处理        }    }}

在AndroidManifest.xml中注册

 <receiver android:name=".receiver.MyBroadcastReceiver">        <!-- 接收短信-->            <action android:name="android.provider.Telephony.SMS_RECEIVED"/>        </receiver>

注意还得要添加权限:

<!--//权限 --><uses-permission android:name = "android.permission.RECEIVE_SMS" />





两种方式对比


注册方式特点使用场景    静态注册常驻,不受任何组件的生命周期影响,应用程序关闭后,如果有信息广播里,程序依然会被系统调用,但是耗电站内存需要时刻监听广播动态注册不是常驻,灵活,跟随组件的生命周期变化,组件结束 == 广播结束,在组件结束是,必须移除广播接收器需要特定时刻监听广播



广播类型及广播的收发

普通广播:
发送一个广播,所以监听该广播的广播接收者都可以监听到该广播
异步广播:
当处理完之后的Intent,依然存在,这时候registerReceiver(BroadcastReceiver,IntentFilter)还能收到他的值,直到把它去掉,不能将处理结果传递给下一个接收者,无法终止广播。
有序广播:
按照接收者的优先级顺序接收广播,优先级别在intent-filter中的priority中声明,-1000到1000之间,值越大,优先级越高,可以终止广播意图的继续传播,接收者可以篡改内容。

有序广播例子:
1.创建两个广播接收者:

public class FirstReceiver extends BroadcastReceiver {    @Override    public void onReceive(Context context, Intent intent) {        String msg = intent.getStringExtra("msg");        Log.d("MyFirstReceiver", msg);        //将数据传输给下一个广播接收者        setResultData("This is the Second Msg From MyFirstReceiver");    }}


public class SecondReceiver extends BroadcastReceiver {    @Override    public void onReceive(Context context, Intent intent) {        //获得上一个广播接收者传过来的数据        String msg = getResultData();        Log.d("MyThirdReceiver", msg);    }}

2.在AndroidManifest.xml中注册三个广播接收者

 <receiver android:name=".receiver.FirstReceiver">            <intent-filter android:priority="100">                <action android:name="OrderBroadcast"/>                </intent-filter>        </receiver>        <receiver android:name=".receiver.SecondReceiver">             <intent-filter android:priority="20">                 <action android:name="OrderBroadcast"/>                 </intent-filter>        </receiver>

3.发送广播:

                Intent mintent = new Intent("OrderBroadcast");                mintent.putExtra("yanner","发送广播");                //发送广播              //  sendBroadcast(mintent);                sendOrderedBroadcast(mintent,null);

打印log:

11-15 20:48:49.283 32069-32069/com.example.administrator.broadcastdemo D/11111: This is the First Msg From MyFirstReceiver
11-15 20:48:49.302 32069-32069/com.example.administrator.broadcastdemo D/1111: This is the Second Msg From MyFirstReceiver


每个接收者都加了一个属性:priority,这个属性表示有序广播中的优先级,值越高表示优先级越高,当广播发出时,优先级最高的便会第一个接收到广播并拦截下来,然后继续往优先级低的传递下去。


总结:

广播接收者接收广播的顺序规则是:

按照priority属性值从大到小排序

priority属性一样时,动态注册广播优先

先接收的广播可以对广播进行拦截,后面接收的广播接收者不再接收到此广播

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

终止广播的方法是:abortBroadcast();