发送自定义广播分类
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方法来发送
接收者可以在
系统默认优先级是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);
注册广播接受者的方式
静态注册
清单文件中声明
指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