BroadcastReceiver

发送自定义广播分类

1.Normal Broadcast:普通广播
2.System Broadcast: 系统广播
3.Ordered broadcast:有序广播
4.Sticky Broadcast:粘性广播(在 android 5.0/api 21中deprecated,不再推荐使用,相应的还有粘性有序广播,同样已经deprecated)
5.Local Broadcast:App应用内广播

作者:kima
链接:http://www.jianshu.com/p/79134d8b3eba
來源:
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

无序广播

广播接收者只要注册接收相应的事件类型,就能接收到的广播。 无序广播数据不可以修改 广播不可以终止

创建一个无序发广播

//创建意图
Intent intent = new Intent();
//设置action--用于接收广播-配置
intent.setAction("com.itheima.xxxx");// ---随意定义
//使用意图携带点数据
intent.putExtra("name", "新闻联播每天晚上7点准时开播");
//sendBroadcast(intent)发送一条无序广播
sendBroadcast(intent);

配置

//配置receiver—在Intent设置的action

    
        
    

创建广播接收者

//创建一个工程接收广播
public class AcceptCustomReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
        abortBroadcast();
        //获取发送自定义广播携带的数据
        String name = intent.getStringExtra("name");
    }
}

有序广播

当广播把消息发送出去后,消息会根据广播接收者的优先级从高到低一级一级地下发消息。---可以拦截消息,也可以修改消息。
特性
 有序广播使用sendOrderedBroadcast方法来发送
 接收者可以在中定义android:priority定义优先级,数字越大优先级越高,优先级的取值范围是: 1000(最高) ~ -1000(最低)谷歌规定最大是1000,但是他的类型其实是int。
系统默认优先级是0,那么想在系统程序之前接收到广播,那么就设置大于0的数,相同优先级下,接收的顺序要看在清单文件中声明注册的顺序
 有序广播可以被拦截或添加数据,优先级高的接收者可以拦截优先级低的 ,使用abortBroadcast方法拦截, 添加数据:通过bundle传递
前面的接收者可以将数据通过setResultExtras(Bundle)方法存放进结果对象,
然后传给下一个接收者,下一个接收者通过代码:Bundle bundle = getResultExtras(true))可以获取上一个接收者存入在结果对象中的数据。

发送广播

Intent intent = new Intent();
intent.setAction("com.itheima.rice");

sendOrderedBroadcast(intent, null, new FinalReceiver(), null, 1,
        "xxx给每个ccc发了1000斤大米", null);

// sendOrderedBroadcast(intent, null, null, null, 1,
// "xxx给每个ccc发了1000斤大米", null);
// 参数1:intent,
// 参数2:接受的权限-不需要-null
// 参数3:广播接受者类型,可以视为最终的广播接受者,
// 参数4:handler
// 参数5:int- 初始码
// 参数6:初始化数据--"广播初始"(携带的数据)
// 参数7:额外数据-null

创建最终接受者—不用再清单文件配置—在发广播的参数3中new对象

public class FinalReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {

        // [1]获取发送广播携带的数据
        String rice = getResultData();
        // [2]给用户一个友好提示
        Toast.makeText(context, "钦差大臣:" + rice, 1).show();
    }
}

接收广播—想要几个优先级就建几个

public class ProvienceReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {

        //[1]getResultData()获取发送广播携带的数据
        String rice = getResultData();
        //[2]给用户一个友好提示
        Toast.makeText(context, "省:" + rice, 1).show();
        //[3] setResultData()修改数据
        setResultData("xxx给每个ccc发了1002斤大米");
        //abortBroadcast();终止广播接收者—但最终的接受者永远也能接收
        // abortBroadcast();
    }
}
public class CityReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        // [1]获取发送广播携带的数据
        String rice = getResultData();
        // [2]给用户一个友好提示
        Toast.makeText(context, "市:" + rice, 1).show();
        // [3]修改数据
        setResultData("xxx给每个ccc发了1002斤大米");
    }
}
public class CountryReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        // [1]获取发送广播携带的数据
        String rice = getResultData();
        // [2]给用户一个友好提示
        Toast.makeText(context, "乡:" + rice, 1).show();
        setResultData("xxx给每个ccc发了1002斤大米");
    }
}


public class NongMinReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        // [1]获取发送广播携带的数据
        String rice = getResultData();
        // [2]给用户一个友好提示
        Toast.makeText(context, "农民收到1002斤大米:" + rice, 1).show();
    }
}

配置receiver—谁先接收就先配置谁—和属性priority="1000"
在意图过滤器上配置优先级android:priority="1000"—取值范围是-1000到1000---只要是int类型值就行


    
        
    



    
        
    



    
        
    



    
        
    

粘性广播

Sticky:粘性
sendStickyBroadcast(intent) 阴魂不散的广播 (粘性的广播)。粘性广播,会一直等待intent指定的事件处理完毕,才会消失。
广播接受者的生命周期都是比较短的,一般接受到广播之后10s左右就会结束,但是有一些广播事件是比较耗时的。比如WIFI状态改变。
Wifi设置:发送wifi状态改变的广播,系统就是通过sendStickyBroadcast来实现的,因为获取wifi状态改变是一个很耗时的操作(获取手机的SSID,并且会获取IP地址等等一系列操作),如果用一般发送广播方式,还没等wifi状态获取完,广播就结束了。

应用内广播

Android中的广播可以跨进程甚至跨App直接通信,且注册是exported对于有intent-filter的情况下默认值是true,由此将可能出现安全隐患如下:
1.其他App可能会针对性的发出与当前App intent-filter相匹配的广播,由此导致当前App不断接收到广播并处理;
2.其他App可以注册与当前App一致的intent-filter用于接收广播,获取广播具体信息
最常见的增加安全性的方案是:
1.对于同一App内部发送和接收广播,将exported属性人为设置成false,使得非本App内部发出的此广播不被接收;
2.在广播发送和接收时,都增加上相应的permission,用于权限验证;
3.发送广播时,指定特定广播接收器所在的包名,具体是通过intent.setPackage(packageName)指定在,这样此广播将只会发送到此包中的App内与之相匹配的有效广播接收器中。
App应用内广播可以理解成一种局部广播的形式,广播的发送者和接收者都同属于一个App。
更多的考虑到的是Android广播机制中的安全性问题。
相比于全局广播,App应用内广播优势体现在:
1.安全性更高;
2.更加高效。
Android v4兼容包中给出了封装好的LocalBroadcastManager类,用于统一处理App应用内的广播问题,使用方式上与通常的全局广播几乎相同,只是注册/取消注册广播接收器和发送广播时将主调context变成了LocalBroadcastManager的单一实例。

//registerReceiver(mBroadcastReceiver, intentFilter);
//注册应用内广播接收器
localBroadcastManager = LocalBroadcastManager.getInstance(this);
localBroadcastManager.registerReceiver(mBroadcastReceiver, intentFilter);
//unregisterReceiver(mBroadcastReceiver);
//取消注册应用内广播接收器
localBroadcastManager.unregisterReceiver(mBroadcastReceiver);
Intent intent = new Intent();
intent.setAction(BROADCAST_ACTION);
intent.putExtra("name", "qqyumidi");
//sendBroadcast(intent);
//发送应用内广播
localBroadcastManager.sendBroadcast(intent);

注册广播接受者的方式

静态注册
清单文件中声明,需要在其中配置指定接收广播的动作(action)
指sd卡未挂载。,


            

          
            


继承broadcastreceiver—onreceive接收广播进行处理
动态注册
这里在清单文件里面注册无效

//动态注册广播接受者—在参1中指定处理广播的接受者
//[1]创建处理广播的screenreceiver广播接受者实例

screenReceiver = new ScreenReceiver();
//[2]创建意图过滤器实例
IntentFilter filter = new IntentFilter();
//设置action--- filter.addAction(可以配置多个)
filter.addAction("android.intent.action.SCREEN_OFF");
filter.addAction("android.intent.action.SCREEN_ON");
//registerReceiver动态注册广播接收者
//参数1:处理这个广播的接收者,参数2:匹配可以接收的广播--意图过滤器
registerReceiver(screenReceiver, filter);

当Activity销毁的时候 应该取消注册广播接收者

@Override
protected void onDestroy() {
    // unregisterReceiver取消注册广播接收者—注册什么就注销什么—在页面销毁之前执行
    unregisterReceiver(screenReceiver);
    //调用父类onDestroy();
    super.onDestroy();
}

定义广播接收者—处理广播

public class ScreenReceiver extends BroadcastReceiver {

    // 当手机锁屏的时候执行
    @Override
    public void onReceive(Context context, Intent intent) {

        // [1]获取当前广播的事件类型
        String action = intent.getAction();
        if ("android.intent.action.SCREEN_OFF".equals(action)) {
            System.out.println("屏幕锁屏");
        } else if ("android.intent.action.SCREEN_ON".equals(action)) {
            System.out.println("屏幕解锁");

        }
    }

}

两种注册广播接受者的区别
代码注册
它不是常驻型广播,也就是说广播跟随程序的生命周期,一旦代码所在进程被杀死,广播接收者就失效。
清单文件注册
是常驻型,也就是说当应用程序关闭后,如果有信息广播来,程序也会被系统调用自动运行。一旦应用程序被部署到手机,广播接收者就会生效,高版本的模拟器(3.2以上)中的接收者,需要启动过一次才能接收到广播。
3.2版本以上出于安全问题:从未启动过的广播接收程序,默认是接收不到广播的,必须有一个界面,然后通过界面启动一次这个程序。

生命周期

广播接收者的生命周期是非常短暂的,在接收到广播的时候创建onReceive()方法结束之后销毁
广播接收者中不要做一些耗时的工作,否则会弹出Application No Response错误对话框。
最好也不要在广播接收者中创建子线程做耗时的工作,因为广播接收者被销毁后进程就成为了空进程,很容易被系统杀掉
广播接收者也一样,在执行生命周期方法onReceive时,也是一个前台进程

广播接收者接收系统发的广播

Ip拨号

定义广播接收者

//定义广播接受者继承BroadcastReceiver
public class OutGoingCallReceiver extends BroadcastReceiver {
    //onReceive当接收到外拨电话的时候执行—清单文件中配置
    @Override
    public void onReceive(Context context, Intent intent) {
        //[0]把刚刚用户存的ip号码给取出来 通过sp取
        SharedPreferences sp = context.getSharedPreferences("config", 0);
        String ipnumber = sp.getString("ipnumber", "");
        //[1]getResultData()获取当前拨打的号码 获取发送广播携带的数据
        String currentNumber = getResultData();
        //[2]setResultData()在当前要拨打的号码前面加上17951
        if (currentNumber.startsWith("0")) {
            setResultData(ipnumber + currentNumber);
        }
    }

}

清单文件配置

// 在清单文件中配置(定义广播接收者后)


    
        
        
    

//加权限PROCESS_OUTGOING_CALLS


SD卡状态监听器

定义广播接收者

public class SdcardReceiver extends BroadcastReceiver {

    //当挂载sd卡 或者卸载sd卡的时候执行
    @Override
    public void onReceive(Context context, Intent intent) {
        //[1]getAction() 获取一下当前广播的事件类型
        String action = intent.getAction();
        //[2]判断一下当前的类型
        if ("android.intent.action.MEDIA_MOUNTED".equals(action)) {
            System.out.println("挂载了~~~~");

        } else if ("android.intent.action.MEDIA_UNMOUNTED".equals(action)) {
            System.out.println("卸载了~~~++~~");
        }
    }

}

清单文件配置

//清单文件中配置

    
        
        

        
    

开机启动广播

定义广播接收者

public class BootReceiver extends BroadcastReceiver {
    // 当手机重新启动的时候执行
    @Override
    public void onReceive(Context context, Intent intent) {
        //把mainActivity这个页面打开
        Intent intent2 = new Intent(context, MainActivity.class);
        //setFlags() 告诉系统添加一个任务栈的环境
        // 注意 当在广播接收者中开启Activity 是没有任务栈的 所以需要我们告诉系统添加一个任务栈的环境
        intent2.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        // 开启activity
        context.startActivity(intent2);
    }
}

清单文件配置


    
        
    


安装和卸载应用


    
        
        
        
    

public class AppStateReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        //getAction() 获取当前广播的事件类型
         String action = intent.getAction();
         if ("android.intent.action.PACKAGE_INSTALL".equals(action)) {
             System.out.println("这个没啥用~~~");
        } else if ("android.intent.action.PACKAGE_ADDED".equals(action)) {
            intent.getData(); //拿到应用的包名
             System.out.println("应用被安装了++++" + intent.getData());
        } else if ("android.intent.action.PACKAGE_REMOVED".equals(action)) {
           System.out.println("应用被卸载了~~~");
        }
    }
}

短信监听器—6.0去掉了


    
        
    

//加上收和发送短信权限


//定义广播接受者
public class SmsReceiver extends BroadcastReceiver {
    //当短信到来的时候执行
    @SuppressWarnings("deprecation")
    @Override
    public void onReceive(Context context, Intent intent) {
        // [1] intent.getExtras().get("pdus");获取短信发送的内容 和 是谁发送的---强转成Object[]
        Object[] object = (Object[]) intent.getExtras().get("pdus");
        //Pdu协议数据单元
        // [2]创建Smsmessage.createFromPdu((byte[]) object2)对象来获取短信的内容
        for (Object object2 : object) {
            SmsMessage smsMessage = SmsMessage.createFromPdu((byte[]) object2);
            //[3] getMessageBody()获取短信发送的内容
            String body = smsMessage.getMessageBody();
            String address = smsMessage.getOriginatingAddress();//谁发送的
            System.out.println("address:" + address + "~~~~~" + body);
        }
    }
}

没有界面的监听器
在清单文件中,将MainActivity的intent-filter配置删除掉,
安卓4.0版本之后为了安全考虑,要求应用程序必须要有界面,必须被用户运行过一次,广播接受者才会生效。
安卓4.0版本的强行停止相当于冻结一个应用,一旦应用程序被用户强行停止了,广播接受者就不会生效了,直到用户手动打开这个应用程序为止
6.0时短信监听完全屏蔽

http://www.jianshu.com/p/79134d8b3eba

你可能感兴趣的:(BroadcastReceiver)