android 学习笔记8-广播接收者 有序 无序广播 案例

1、广播接收者-可以在清单文件中定义,也可以在代码中注册。
    如果在清单文件中注册的话,就算应用的进程没有启动,收到广播也会自动启动进程的。有的时候不想一直接收,就在代码中注册
        (例如:玩游戏电量低的时候,当退出应用就不用接收了,不然用户会莫名其妙地接收到你弹的一些提示操作)。


    系统在产生某个事件时发送广播,应用程序使用广播接收者接收这个广播,就知道系统产生了什么事件。
    Android系统在运行的过程中,会产生很多事件,比如开机、电量改变、收发短信、拨打电话、屏幕解锁


    当一条广播被发送出来时,系统是在所有清单文件中遍历,通过匹配意图过滤器找到能接收这条广播的广播接收者
    
    
2、IP拨号器-利用接收拨打电话的广播,修改广播内携带的电话号码,重新发送广播。
    拨号器不会打电话,只会发一条打电话的广播,打电话应用接收到了广播才将电话拨打出去。
    因为拨打电话是一种有序的广播,因此可以修改你自己的应用优先级为1000,如果是无序的就没有办法了。
    
    a,定义一个广播接收者-只需要继承BroadcastReceiver就可以了
        public class CallReceiver extends BroadcastReceiver {


            //当广播接收者接收到广播时,此方法会调用
            @Override
            public void onReceive(Context context, Intent intent) {
                String number = getResultData();//拿到用户拨打的号码
                setResultData("12345" + number);//修改广播内的号码
            }
        }
    
    b,在清单文件中定义该广播接收者接收的广播类型-我们接收打电话的广播。
        一定要配置intent-filter,不然定义了就没有,都不知道收什么广播。
        <receiver android:name="com.example.ip.CallReceiver">//这个是你定义的广播接收者的名称
            <intent-filter >
                <action android:name="android.intent.action.NEW_OUTGOING_CALL"/>//这个是意图过滤器的一个动作,你想接收的广播类型
            </intent-filter>
        </receiver>
        
    c,接收打电话广播需要权限
        <uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS"/>
        
    备注:即使广播接收者的进程没有启动,当系统发送的广播可以被该接收者接收时,系统会自动启动该接收者所在的进程。
    广播是通过intent发送的,intent中会携带一个action,系统会在所有清单文件中寻找,看哪一个广播接收者的intent-filter(action和data都要匹配)和广播中的intent是匹配的,那么这个广播接收者就会收到这条广播
    
    代码演示:
        CallReceiver.java
        public class CallReceiver extends BroadcastReceiver {


            //收到广播时调用
            @Override
            public void onReceive(Context context, Intent intent) {
                String number = getResultData();//拿到用户拨打的号码,因为存放就是直接存放的,取就直接取了好了
                String newNumber = "12345" + number;
                setResultData(newNumber);   //把修改后的号码放入广播中
                
                abortBroadcast();//拦截是无效的,因为手机有个ResultReviever一定会而且是最后一个接收到广播,可以修改号码使之失效
            }
        }


3、短信拦截
    短信应用并不会接收短息,只是接收到短信广播,短信是系统接收的,是一个有序的广播,我们自己也可以收,把我们应用优先级提高就可以先于系统应用接收到短信。
    
    a,定义一个短信的广播接收者
    public void onReceive(Context context, Intent intent) {
            //拿到广播里携带的短信内容
            Bundle bundle = intent.getExtras();//因为存的时候就是放到Bundle这个对象中的,所以取也是先取Boudle
            //数组中每个元素就是一条短信
            Object[] objects = (Object[]) bundle.get("pdus");//pdu:协议数据单元,取出来的是一个object数组
            for(Object ob : objects ){
                //通过object对象创建一个短信对象
                SmsMessage sms = SmsMessage.createFromPdu((byte[])ob);//接收的是一个字符数组,因为ob这个对象本身就是字节数组,强转下就可以
                System.out.println(sms.getMessageBody());
                System.out.println(sms.getOriginatingAddress());
            }
        }
    系统创建广播时,把短信存放到一个数组,然后把数据以pdus为key存入bundle,再把bundle存入intent
    
    b,清单文件中配置广播接收者接收的广播类型,注意要设置优先级属性,要保证优先级高于短信应用,才可以实现拦截
    <receiver android:name="com.example.smslistener.SmsReceiver">
            <intent-filter android:priority="1000">//设置优先级,google有些api会隐藏不让上层程序员用,没有提示,需要手动敲下。
                <action android:name="android.provider.Telephony.SMS_RECEIVED"/>
            </intent-filter>
        </receiver>
    
    c,需要添加权限
        <uses-permission android:name="android.permission.RECEIVE_SMS"/>


        
    代码演示:
        MainActivity.java不需要任何代码
        SmsReceiver.java:
        public class SmsReceiver extends BroadcastReceiver {
            @Override
            public void onReceive(Context context, Intent intent) {
                Bundle bundle = intent.getExtras();//取出短信内容
                //数组中的每一个元素,就是一条短信
                Object[] objects = (Object[]) bundle.get("pdus");
                for (Object object : objects) {
                    //把数组中的元素转换成短信对象
                    SmsMessage sms = SmsMessage.createFromPdu((byte[]) object);
                    String address = sms.getOriginatingAddress();//获取对方号码
                    String body = sms.getMessageBody();//获取短信内容
                    
                    if("12345".equals(address)){
                        abortBroadcast(); //拦截短信,终止广播
                    }
                }
                
            }


        }
        清单文件:
        <receiver android:name="com.example.smslanjie.SmsReceiver">
<intent-filter android:priority="1000">
<action android:name="android.provider.Telephony.SMS_RECEIVED"/>
</intent-filter>
</receiver>


    温馨提示:把应用入口关掉,界面就不会显示图标了,可以隐藏应用(把下面的删掉)
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />
            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>


    在4.0之后,广播接收者所在的应用必须启动过一次,才能生效,
        如果广播接收者所在应用被用户手动关闭了,那么再也不会启动了,直到用户再次手动启动该应用   


    
4、开机自动启动软件    
    接收一个开机广播,在广播接收者中实现我们要做的逻辑操作
    
    a,定义广播接收者
@Override
public void onReceive(Context context, Intent intent) {//注意这个intent是广播的intent,不能启动这个要启动it这个
//开机的时候就启动
Intent it = new Intent(context, MainActivity.class);
context.startActivity(it);
        }
        
    b,清单文件中配置接收开机广播


<receiver android:name="com.example.test.BootReceiver">
            <intent-filter >
                <action android:name="android.intent.action.BOOT_COMPLETED"/>
            </intent-filter>
        </receiver>
    
    c,权限
        <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
        
    d,以上代码还不能启动MainActivity,因为广播接收者的启动,并不会创建任务栈,那么没有任务栈,就无法启动activity
        手动设置创建新任务栈的flag
it.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);    

        
        
    代码演示:
    MainActivity.java:
        public class MainActivity extends Activity {


            @Override
            protected void onCreate(Bundle savedInstanceState) {
                super.onCreate(savedInstanceState);
                setContentView(R.layout.activity_main);
            }


            @Override
            public void onBackPressed() {//重写下onBackPressed,让返回键失效,home是系统处理的,只能通过任务栈去实现劫持
            }
        }
    
    BootReceiver.java
    public class BootReceiver extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {
            Intent it = new Intent(context, MainActivity.class);
            //创建新的任务栈,因为这行代码执行时,没有任务栈
            it.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            context.startActivity(it);
        }
    }
    清单文件:
        <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
    <receiver android:name="com.example.test.BootReceiver">
<intent-filter >
<action android:name="android.intent.action.BOOT_COMPLETED"/>
</intent-filter>
</receiver>
        
    特别注意:在广播接收者中启动一个activity是不行的,因为广播接收者不是一个上下文,所以不能调用上下文里面的方法
        需要设置创建新的任务栈启动,
        it.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    


5、自定义广播-开发中一般比较少用到,比如给平台开发一些接口API
    我们发送广播是通过意图intent发送的,只需要指定一个action就行,如果没有action那谁都接收不了了
    
    在需要接收的这个广播的应用清单文件配置下需要接收的广播action就行
    例如:
        public class MainActivity extends Activity {
            @Override
            protected void onCreate(Bundle savedInstanceState) {
                super.onCreate(savedInstanceState);
                setContentView(R.layout.activity_main);
            }


            public void click(View v){
                Intent intent = new Intent();
                intent.setAction("a.b.c");
                //发送自定义无序广播
                sendBroadcast(intent);
            }
        }
    
6、广播的两种类型
    无序广播:所有跟广播的intent匹配的广播接收者都可以收到该广播,并且是没有先后顺序(同时收到)
    有序广播:所有跟广播的intent匹配的广播接收者都可以收到该广播,但是会按照广播接收者的优先级来决定接收的先后顺序
    
    优先级的定义:-1000~1000
结果接收者:所有广播接收者都接收到广播之后,它才接收,并且一定会接收(比如说打电话应用,一定会接收到打电话广播,所以你拦截也没有用)
bortBroadCast:阻止其他接收者接收这条广播,类似拦截,只有有序广播可以被拦截
    
    例如:
        public class MainActivity extends Activity {


            @Override
            protected void onCreate(Bundle savedInstanceState) {
                super.onCreate(savedInstanceState);
                setContentView(R.layout.activity_main);
            }




            public void click(View v){
                Intent intent = new Intent();
                intent.setAction("a.b.c");
                //发送自定义有序广播
                //resultReceiver:在所有广播接收者都收到广播之后,才会收到,一定是最后一个收到,并且一定能收到
                sendOrderedBroadcast(intent, null, new MyReceiver(), null, 0, "广播的内容", null);
            }
            
            class MyReceiver extends BroadcastReceiver{


                @Override
                public void onReceive(Context context, Intent intent) {
                    String order = getResultData();
                    System.out.println("最后一个收到" + order);
                    
                }
                
            }
        }
        
    注意:发送有序自定义广播时候,resultReceiver参数设置了,就有一个在所有广播接收者都收到广播之后,最后收到,可以在这个里面实现逻辑操作
    
    
7、代码注册广播接收者-一般在服务中注册,服务开启就注册,停止就反注册
    Android四大组件都要在清单文件中注册
    广播接收者可以使用清单文件注册
        一旦应用部署,广播接收者就生效了,直到用户手动停止应用或者应用被删除
    广播接收者可以使用代码注册
        需要广播接收者运行时,使用代码注册,不需要时,可以使用代码解除注册
    电量改变、屏幕开关,必须使用代码注册


    //1.创建广播接收者对象
    receiver = new ScreenOnOFFReceiver();
    //2.创建意图过滤器对象
    IntentFilter filter = new IntentFilter();
    //指定接收什么广播
    filter.addAction(Intent.ACTION_SCREEN_OFF);
    filter.addAction(Intent.ACTION_SCREEN_ON);
    //3.注册广播接收者
    registerReceiver(receiver, filter);
                
    代码演示:
    MainActivity.java
        public class MainActivity extends Activity {
            @Override
            protected void onCreate(Bundle savedInstanceState) {
                super.onCreate(savedInstanceState);
                setContentView(R.layout.activity_main);
            }


            public void start(View v){//点击按钮开启服务,开启服务就去注册广播接收者
                Intent intent = new Intent(this, RegisterService.class);
                startService(intent);
            }
            public void stop(View v){//点击按钮停止服务,就去反注册广播接收者
                Intent intent = new Intent(this, RegisterService.class);
                stopService(intent);
            }
        }


    RegisterService.java//定义一个服务类  
        public class RegisterService extends Service {
            private ScreenOnOFFReceiver receiver;//定义一个广播接收者对象
            @Override
            public IBinder onBind(Intent intent) {//没有用到服务中的方法,所以直接返回一个null
                return null;
            }


            @Override
            public void onCreate() {
                super.onCreate();
                //1.创建广播接收者对象
                receiver = new ScreenOnOFFReceiver();
                //2.创建意图过滤器对象
                IntentFilter filter = new IntentFilter();
                //指定接收什么广播
                filter.addAction(Intent.ACTION_SCREEN_OFF);
                filter.addAction(Intent.ACTION_SCREEN_ON);
                //3.注册广播接收者
                registerReceiver(receiver, filter);
            }
            
            @Override
            public void onDestroy() {//服务停止就反注册
                super.onDestroy();
                //反注册广播接收者
                unregisterReceiver(receiver);
            }
            
        }
    
    ScreenOnOFFReceiver.java//定义一个广播接收者
        public class ScreenOnOFFReceiver extends BroadcastReceiver {
            @Override
            public void onReceive(Context context, Intent intent) {
                String action = intent.getAction();
                if(Intent.ACTION_SCREEN_ON.equals(action)){
                    System.out.println("屏幕开");
                }
                else if(Intent.ACTION_SCREEN_OFF.equals(action)){
                    System.out.println("屏幕关");
                }
            }
        }
        
        
    这样就实现了代码注册和反注册功能
    
    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值