广播接收者的本质就是一个全局的监听器,用于监听系统全局的广播消息,比如:拨打电话、收发短信、屏幕解锁等事件产生了,系统会发送广播,只要应用程序接受到这条广播,就知道系统发生了相应的事件,从而执行相应的代码。
创建一个广播接收者:
- 声明一个类继承自BroadcastReceiver,重写BroadcastReceiver的onReceiver方法即可。
-
指定BroadcastReceiver可以匹配的Intent:
a.在清单文件中进行指定
b.使用代码动态指定(特殊的广播接收者必须使用代码的方式进行动态指定)
下面创建一个广播接收者:
1.声明一个类继承自BroadcastReceiver,重写BroadcastReceiver的onReceiver方法即可。
/**
* Created by 春水碧于天 on 2017/1/22.
*/
public class SmsReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if(action.equals("android.provider.Telephony.SMS_RECEIVED")){
Toast.makeText(context,"来信息了!",Toast.LENGTH_SHORT).show();
}else if(action.equals("android.intent.action.PHONE_STATE")){
Toast.makeText(context,"来电话了!",Toast.LENGTH_SHORT).show();
}
}
}
2.在清单文件中进行配置(application节点下):
<receiver android:name=".SmsReceiver">
<intent-filter>
<action android:name="android.provider.Telephony.SMS_RECEIVED"/>
<action android:name="android.intent.action.PHONE_STATE"/>
</intent-filter>
</receiver>
注:一个广播接收者可以监听多个事件,此处监听了电话状态的改变,接收短信。此处还需要添加上两个权限:
<uses-permission android:name="android.permission.RECEIVE_SMS"/>
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
当配置的action 的事件发生了 onReceive方法就会执行
运行效果:
对于一些比较频繁的广播事件比如屏幕解锁,锁屏,电池电量变化,这样的广播接收者在清单文件里面注册无效。需要使用代码进行动态注册
监听屏幕锁屏事件的广播接收者:
1.声明一个类继承自BroadcastReceiver,重写BroadcastReceiver的onReceiver方法即可。
/**
* Created by 春水碧于天 on 2017/1/22.
*/
public class SpecialReceiver extends BroadcastReceiver{
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if(action.equals("android.intent.action.SCREEN_ON")){
Toast.makeText(context,"屏幕解锁了",Toast.LENGTH_SHORT).show();
}else if(action.equals("android.intent.action.SCREEN_OFF")){
Toast.makeText(context,"屏幕锁屏了",Toast.LENGTH_SHORT).show();
}
}
}
2.在MainActivity中对要监听的事件进行动态的注册:
public class MainActivity extends AppCompatActivity {
private SpecialReceiver specialReceiver;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//动态的去注册屏幕解锁和锁屏的广播
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction("android.intent.action.SCREEN_ON");
intentFilter.addAction("android.intent.action.SCREEN_OFF");
//创建一个广播接收者的实例
specialReceiver = new SpecialReceiver();
/**
* 参数1:BroadcastReceiver receiver:
* 参数2:IntentFilter filter
*/
registerReceiver(specialReceiver,intentFilter);
}
@Override
protected void onDestroy() {
super.onDestroy();
//动态注册的广播收者一定都要取消注册才行
unregisterReceiver(specialReceiver);
}
}
在MainActivity销毁的时候,一定unregisterReceiver(specialReceiver)
,对广播接收者取消注册。
否则会报下面的错误:
Activity com.example.reviewbroadcastreciver.MainActivity has leaked IntentReceiver com.example.reviewbroadcastreciver.SpecialReceiver@752c889 that was originally registered here. Are you missing a call to unregisterReceiver()?
运行效果:
这样子做的话如果MainActivity销毁之后,也就是广播接收者取消注册了,就不会再监听到锁屏状态的变化了,这应该也是谷歌出于保证系统流畅度的设计,避免程序间的唤醒以达到节省内存的目的,如果需要时刻监听这种比较频繁的广播事件则可以再Service中进行动态注册。
广播发送者:
广播既可以由Android系统进行发送,也可以由我们自己的程序来向外发送广播。
在程序中发送广播十分简单,只需要调用Context的sendBroadcast(Intent intent)
方法即可,这条广播将会启动intent参数所对应的BroadcastReceiver.
广播分为:
无序广播:通过Context.sendBroadcast()方法来发送,所有的广播接收者(BroadcastReceiver)的接收顺序不确定,这种方式的效率更高,但是但BroadcastReceiver无法使用setResult系列、getResult系列及abort(中止)系列API。
有序广播:是通过Context.sendOrderedBroadcast来发送,所有的receiver依次执行。
BroadcastReceiver可以使用setResult系列函数来结果传给下一个BroadcastReceiver,通过getResult系列函数来取得上个BroadcastReceiver返回的结果,并可以abort系列函数来让系统丢弃该广播,使用该广播不再传送到别的BroadcastReceiver。
可以通过在intent-filter中设置android:priority属性来设置receiver的优先级,优先级相同的receiver其执行顺序不确定。
如果BroadcastReceiver是代码中注册的话,且其intent-filter拥有相同android:priority属性的话,先注册的将先收到广播。
简要概述:
无序广播:广播不可以被终止 数据不可以被修改
有序广播:按照优先级一级一级的接收 有序广播可以被终止 数据可以被修改
发送一个无序广播:
//发送一个无序广播
public void Click(View v){
Intent intent = new Intent();
intent.setAction("com.example.reviewbroadcastreciver");
intent.putExtra("msg","你妈叫你们回家吃饭啦……");
sendBroadcast(intent);
}
发送一个有序广播:
//发送一个有序广播
//发送一个有序广播
public void OrderClick(View v){
Intent intent = new Intent();
intent.setAction("com.example.reviewbroadcastreciver");
//第三个参数为最终要执行的广播接收者
sendOrderedBroadcast(intent, null, new FinalReceiver(), null, 1, "你妈叫你回家吃饭了!", null);
}
}
FinalReceiver.java
/**
* 最终执行的Receiver,不需要在清单文件中配置
* Created by 春水碧于天 on 2017/1/23.
*/
public class FinalReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
String msg = getResultData();
Toast.makeText(context,"报告奶奶,爸爸妈妈都叫我回家吃饭了!",Toast.LENGTH_SHORT).show();
}
}
接收一个有序广播:
创建4个广播接收者用于测试:
在清单文件中进行配置:
<receiver android:name=".FirstReceiver">
<!--设置接收广播的优先级-->
<intent-filter android:priority="1000">
<action android:name="com.example.reviewbroadcastreciver" />
</intent-filter>
</receiver>
<receiver android:name=".SecondReceiver">
<!--设置接收广播的优先级-->
<intent-filter android:priority="600">
<action android:name="com.example.reviewbroadcastreciver" />
</intent-filter>
</receiver>
<receiver android:name=".ThirdReceiver">
<!--设置接收广播的优先级-->
<intent-filter android:priority="200">
<action android:name="com.example.reviewbroadcastreciver" />
</intent-filter>
</receiver>
<receiver android:name=".FourthReceiver">
<!--设置接收广播的优先级-->
<intent-filter android:priority="0">
<action android:name="com.example.reviewbroadcastreciver" />
</intent-filter>
</receiver>
<intent-filter android:priority="1000">
配置接收广播的优先级priority的取值从-1000到1000,数值越大优先级越高。
这里只写出第一个广播接收者,其它的代码与之相同。
/**
* Created by 春水碧于天 on 2017/1/23.
*/
public class FirstReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
String msg = getResultData();
Toast.makeText(context,"FirstReceiver"+msg,Toast.LENGTH_SHORT).show();
}
}
运行效果:
可以看到每个广播接收者按照清单文件中配置的优先级依次接收
使用setResult修改广播发送的内容:
SecondReceiver.Java
/**
* Created by 春水碧于天 on 2017/1/23.
*/
public class SecondReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
String msg = getResultData();
setResultData("你爸爸叫你回家吃饭啦…………");
Toast.makeText(context,"SecondReceiver"+msg,Toast.LENGTH_SHORT).show();
}
}
使用abortBroadcast( )进行广播的截断
ThirdReceiver.Java
/**
* Created by 春水碧于天 on 2017/1/23.
*/
public class ThirdReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
String msg = getResultData();
Toast.makeText(context,"ThirdReceiver"+msg,Toast.LENGTH_SHORT).show();
abortBroadcast(); //进行广播拦截,不再向下传递
}
}
运行效果:
可见在 ThirdReceiver 获取的内容为SecondReceiver修改过
的,FourthReceiver因为广播在ThirdReceiver中被截断了,所以没有收到广播,FinalReceiver为最后执行的广播。
┭┮﹏┭┮ O(∩_∩)O