Android BroadcastReceiver 详解(下)

182 阅读5分钟

这是我参与11月更文挑战的第10天,活动详情查看:2021最后一次更文挑战

文章目录

有序广播的拦截

在有序广播接收者中,可以调用abortBroadcast()方法,终止有序广播继续向后传递

接着上一节的例子,当前优先级最高的是 LowReceiver,可以在处理接受有序广播的代码中终止广播

public class LowReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        //区分广播的“频道”
        String action = intent.getAction();
        if("CCTV5".equals(action)){
            String date = intent.getStringExtra("date");
            Log.d("BROADCAST","LowReceiver->onReceive();时间:"+date);
        }else if("CCTV1".equals(action)){
            int number = intent.getIntExtra("_number",-999);
            abortBroadcast();
            Log.d("BROADCAST","LowReceiver->onReceive();_number:"+number);
        }else{

        }

    }
}

重新运行程序,发送有序广播

观察日志,只有

D/BROADCAST: LowReceiver->onReceive();_number:0

注意
只能拦截有序广播,不能对无序广播使用

如果我们在无序广播中使用会报错

在这里插入图片描述

广播的篡改

在有序广播的接收者中,可以通过setResult???的方法,向广播中添加数据,优先级更低的广播接收者可以通过调用对应的getResult???的方法获取此前被添加进的数据

上一节中我们设置的优先级如下:

D/BROADCAST: LowReceiver->onReceive();_number:0
D/BROADCAST: MidReceiver->onReceive();_number:0
D/BROADCAST: InnerLowReceiver->onReceive();_number:0
D/BROADCAST: InnerMidReceiver->onReceive();_number:0
D/BROADCAST: InnerHighReceiver->onReceive();_number:0
D/BROADCAST: HighReceiver->onReceive();_number:0

按照这个优先级我们需要篡改数据如下:

LowReceiver	说:老王今天来了
MidReceiver 说:老王今天来了,还偷拍了小美
InnerLowReceiver 说:老王今天来了,还偷拍了小美,并且ps了
InnerMidReceiver
InnerHighReceiver
HighReceiver 

修改 LowReceiver

 @Override
    public void onReceive(Context context, Intent intent) {
        //区分广播的“频道”
        String action = intent.getAction();
        if("CCTV5".equals(action)){
            ......
        }else if("CCTV1".equals(action)){
            int number = intent.getIntExtra("_number",-999);
            //拦截广播
            //abortBroadcast();
            //添加数据,向后面的接收者传递
            setResultData("老王今天来了");
            Log.d("BROADCAST","LowReceiver->onReceive();_number:"+number+",说:老王今天来了");
        }else{
        }
    }

修改 MidReceiver

public class MidReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        //区分广播的“频道”
        String action = intent.getAction();
        if ("CCTV5".equals(action)) {
            ......
        } else if ("CCTV1".equals(action)) {
            int number = intent.getIntExtra("_number", -999);
            //获取前一个接收者传递的数据
            String str = getResultData();
            //篡改数据
            setResultData("老王今天来了,还偷拍了小美");

            Log.d("BROADCAST", "MidReceiver->onReceive();_number:" + number + "收到:" + str + ",重新说:老王今天来了,还偷拍了小美");
        } else {
        }
    }
}

修改 InnerLowReceiver

private class InnerLowReceiver extends BroadcastReceiver {

        @Override
        public void onReceive(Context context, Intent intent) {
            //区分广播的“频道”
            String action = intent.getAction();
            if ("CCTV5".equals(action)) {
                ......
            } else if ("CCTV1".equals(action)) {
                int number = intent.getIntExtra("_number", -999);
                //获取前一个接收者传递的数据
                String str = getResultData();
                //篡改数据
                setResultData("老王今天来了,还偷拍了小美,并且Ps了");

                Log.d("BROADCAST", "InnerLowReceiver->onReceive();_number:" + number + "收到:" + str + ",重新说:老王今天来了,还偷拍了小美,并且Ps了");
            } else {

            }
        }
    }

其余 InnerMidReceiver、InnerHighReceiver、HighReceiver 的onReceive方法都改为类似

public class HighReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        //区分广播的“频道”
        String action = intent.getAction();
        if("CCTV5".equals(action)){
            ......
        }else if("CCTV1".equals(action)){
            int number = intent.getIntExtra("_number",-999);
            //获取前一个接收者传递的数据
            String str = getResultData();
            Log.d("BROADCAST","HighReceiver->onReceive();_number:"+number+",收到:"+str);
        }else{

        }
    }
}

运行程序,先注册内部接收者,然后发送有序广播,观察日志

LowReceiver->onReceive();_number:0,说:老王今天来了
MidReceiver->onReceive();_number:0收到:老王今天来了,重新说:老王今天来了,还偷拍了小美
InnerLowReceiver->onReceive();_number:0收到:老王今天来了,还偷拍了小美,重新说:老王今天来了,还偷拍了小美,并且Ps了
InnerMidReceiver->onReceive();_number:0,收到:老王今天来了,还偷拍了小美,并且Ps了
InnerMidReceiver->onReceive();_number:0,收到:老王今天来了,还偷拍了小美,并且Ps了
HighReceiver->onReceive();_number:0,收到:老王今天来了,还偷拍了小美,并且Ps了

管理呼出电话

当 Android 设备尝试呼出电话时,会由系统发出有序广播,并且通过setResultData(String)方法将电话号码封装,最后,系统的呼叫程序将会接收到该广播,并通过getResultData()方法获取电话号码,实现呼叫

管理呼出电话原理:自定义广播接收者,接收系统的呼出电话广播,并通过getResultData()获取呼出的电话号码,对电话号码进行判断,如果符合设定规则,通过setResultData()重新设置电话号码即可

栗子:拨打10086时改为10000

自定义 ProcessOutGoingCallReceiver

public class ProcessOutGoingCallReceiver extends BroadcastReceiver{
    @Override
    public void onReceive(Context context, Intent intent) {
        String number = getResultData();
        Log.d("BROADCAST","Number"+number);
        if("10086".equals(number)){
            setResultData("10000");
            Log.d("BROADCAST","符合规则,改为10000");
        }
    }
}

AndroidManifest

增加权限

<uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS"/>

注册

<receiver android:name=".ProcessOutGoingCallReceiver">
	<intent-filter>
		<category android:name="android.intent.category.DEFAULT"/>
		<action android:name="android.intent.action.NEW_OUTGOING_CALL"/>
	</intent-filter>
</receiver>

注意
确认在应用中“电话权限”是否打开

首先拨打 12345,然后拨打 10086,观察日志

D/BROADCAST: Number12345
D/BROADCAST: Number10086
D/BROADCAST: 符合规则,改为10000

如何获取更高的有序广播者的优先级

1、使用最大的 priority 属性注册具体实施业务的广播接收者
2、使用粘性 Service,在 onCreate() 时动态注册具体实施业务的广播接受者
3、使用静态的方式注册监听开机广播(BOOT_COMPLETED)的广播接收者,并在收到该广播后,使用启动模式激活 Service
4、如果某些版本的 Android 系统不允许监听开机广播,只能尽可能的监听各种系统广播

源码下载