欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

android全方位解析BroadcastReceiver

程序员文章站 2022-08-11 10:01:35
概念: 作为android的四大,相信很多人都知道broadcastreceiver,那什么是broadcastreceiver ? 直译是“广播接收者”...

概念:

作为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.在清单文件注册

 
        
            
                
                
            
        

注意这是自定义广播。

也可以使用系统广播:

以接收短信为例:

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中注册
 
        
            

        

注意还得要添加权限:


两种方式对比


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




广播类型及广播的收发

普通广播:

发送一个广播,所以监听该广播的广播接收者都可以监听到该广播

异步广播:

当处理完之后的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中注册三个广播接收者

 

            

                
                
        

        
             
                 
                 
        

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