BroadcastReceiver简介
BroadcastReceiver也就是”广播接收者”的意思, 顾名思义, 它就是用来接收来自系统和应用中的广播.
在Android系统中, 广播体现在方方面面, 例如当开机完成后系统会产生一条广播,接收到这条广播就能实现开机启动服务的 功能;当网络状态改变时系统会产生一条广播,接收到这条广播就能及时地做出提示和保存数据等橾作;当电池电量改变时,系统会产生一条广播,接收到这条广播就能在电量低时告知用户及时保存进度,等等。
Android中的广播机制设计的非常出色,很多事情原本需要开发者亲自操作的,现在只需等待广播告知自己就可以了,大大减少了开发的工作量和开发周期。而作为应用开发者,就需要数练掌握Android系统提供的一个开发利器,那就是 BroadcastReceiver
广播接收器的类型
1,Normal broadcasts:默认广播
发送一个默认广播使用Context.sendBroadcast()方法,普通广播对于多个接收者来说是完全异步的,通常每个接收者都无需 等待即可以接收到广播,接收者相互之间不会有影响。对于这种广播,接收者无法终止广播,即无法阻止其他接收者的接收动作。
2, Ordered broadcasts:有序广播
发送一个有序广播使Context.sendOrderedBroadcast()方法,有序广播比较特殊,它每次只发送到优先级较高的接收者那 里,然后由优先级高的接受者再传播到优先级低的接收者那里,优先级高的接收者有能力终止这个广播。
3, Sticky Broadcast:粘牲广播
当处理完之后的Intent,依然存在,直到你把它去掉。
广播接收器的两种注册方法
静态注册
静态注册是在AndroidManifest.xml文件中配置。
创建一个广播接收器
MyReceiver1.java
* 自定义的广播接收器
*/
public class MyReceiver1 extends BroadcastReceiver {
public MyReceiver1() {
}
//接收的方法
@Override
public void onReceive(Context context, Intent intent) {
String info = intent.getStringExtra("info");
Toast.makeText(context, info, Toast.LENGTH_SHORT).show();
}
}
清单文件
<!--表示该receiver有效, 并且可以在外部访问-->
<receiver
android:name=".MyReceiver1"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="com.lulu.action.MY_BROADCAST"/>
</intent-filter>
</receiver>
MainActivity.java
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
//发送一个普通的广播
public void sendNormal(View view){
//发送广播的"动作", 这里的action和接收器过滤器中的action一一对应
Intent intent = new Intent("com.lulu.action.MY_BROADCAST");
intent.putExtra("info", "广播发送示例");
this.sendBroadcast(intent);
}
}
xml文件就不给出了, 就是一个button.
下面就是该段代码的演示:
动态注册
动态注册需要在代码中动态的指定广播地址并注册,通常我们是在Activity或Service注册一个广播
MyReceiver2.java
public class MyReceiver2 extends BroadcastReceiver {
public MyReceiver2() {
}
@Override
public void onReceive(Context context, Intent intent) {
Toast.makeText(context, "动态的注册广播接收器", Toast.LENGTH_SHORT).show();
}
}
MainActivity.java
package com.lulu.lbroadcasereceiver;
import android.content.Intent;
import android.content.IntentFilter;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
public class MainActivity extends AppCompatActivity {
private MyReceiver2 receiver2 = new MyReceiver2();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
//完成广播注册
@Override
protected void onResume() {
super.onResume();
IntentFilter filter = new IntentFilter();
filter.addAction("com.lulu.action.MY_BROADCAST");
registerReceiver(receiver2, filter);
}
//完成解除注册
@Override
protected void onPause() {
super.onPause();
unregisterReceiver(receiver2);
}
}
注意:
代码注册中, 收到广播的先后和注明优先级最后的他们的先后 是随机的
如果没有优先级, 代码注册收到的为最先
有序广播
发送有序广播:sendOrderedBroadcast()
在注册广播中的中使用android:priority属牲。这个属牲的范围在-1000到1000,数值越大,优先级越高。
在广播接收器中使用setResultExtras方法将一个Bundle对象设置为结果集对象,传递到下一个接收者那里,这样优先级低的 接收者可以用getResultExtras获取到最新的经过处理的信息集合。
使用sendOrderedBroadcast方法发送有序广播时,需要一个权限参数,如果为null表示不要求接收者声明指定的权限,如果不为null,则表示接收者若要接收此广播,需声明指定权限。这样做是从安全角度考虑的,例如系统的短信就是有序 广播的形式,一个应用可能是具有拦截垃圾短信的功能,当短信到来时它可以先接受到短信广播,必要时终止广播传递, 这样的软件就必须声明接收短信的权限。终止广播传递 abortBroadcast();
示例代码:
广播发送
//发送一个有序广播
public void sendOrderClick(View view){
Intent intent = new Intent("com.lulu.action.MY_BROADCAST2");
//参数: intent, 接收权限
this.sendOrderedBroadcast(intent, null);
}
下面是两个Receiver
public class MyReceiver3 extends BroadcastReceiver {
public MyReceiver3() {
}
@Override
public void onReceive(Context context, Intent intent) {
Bundle data = getResultExtras(false);
String info = data.getString("info");
Toast.makeText(context, "有序广播-1" + info, Toast.LENGTH_SHORT).show();
}
}
public class MyReceiver4 extends BroadcastReceiver {
public MyReceiver4() {
}
@Override
public void onReceive(Context context, Intent intent) {
Toast.makeText(context, "有序广播-2", Toast.LENGTH_SHORT).show();
Bundle data = new Bundle();
data.putString("info", "钓鱼岛是中国的");
this.setResultExtras(data);
//中断有序广播
// this.abortBroadcast();
}
}
清单文件
<receiver
android:name=".MyReceiver3"
android:enabled="true"
android:exported="true" >
<intent-filter android:priority="100">
<action android:name="com.lulu.action.MY_BROADCAST2"/>
</intent-filter>
</receiver>
<receiver
android:name=".MyReceiver4"
android:enabled="true"
android:exported="true">
<intent-filter android:priority="200">
<action android:name="com.lulu.action.MY_BROADCAST2"/>
</intent-filter>
</receiver>
优先级顺序:
代码注册(有优先级) -> 静态注册(有优先级) -> 代码注册-> 静态注册
粘性广播
发送粘性广播使用:sendStickyBroadcast(intent);
发这个广播需要权限
去掉是用这个方法removeStickyBroadcast(intent);
sendStickyOrderedBroadcast():这个方法具有有序广播的特性也有粘性广播的特性;
在这个方法发来的广播中,代码注册方式中,收到广播先后次序为:注明优先级的、代码注册的、没有优先级的;如果都没 有优先级,代码注册收到为最先。
粘性广播在API23中已经过时
接收系统广播
开机启动
我们经常会有这样的应用场合,比如消息推送服务,需要实现开机启动的功能。要实现这个功能,我们就可以订阅系统“启动 完成”这条广播,接收到这条广播后我们就可以启动自己的服务了。
<intent-filter>
<!-注册开机广播地址-->
<actionandroid:name="android.intent.action.BOOT_COMPLETED"/>
<categoryandroid:name="android.intent.category.DEFAULT"/>
</intent-filter>
这个开机广播地址,从安全角度考虑,系统要求必须声明接收开机启动广播的权限
<uses-permission android:name=
"android.permission.RECEIVE_BOOT_COMPLETED"/>
网络检测
比如用户浏览网络信息时,网络突然断开,我们要及时地提醒用户网络已断开。要实现这个功能,我们可以接收网络状态改变这样一条广播,当由连接状态变为断开状态时,系统就会发送一条广播,我们接收到之后,再通过网络的状态做出相 应的操作。
清单文件配置
<receiver
android:name=".MyReceiver5"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
</intent-filter>
</receiver>
问网络状态权限:
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
MyReceiver5.java
public class MyReceiver5 extends BroadcastReceiver {
public MyReceiver5() {
}
@Override
public void onReceive(Context context, Intent intent) {
ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo info = cm.getActiveNetworkInfo();
if(info != null){
String name = info.getTypeName();
Toast.makeText(context, name, Toast.LENGTH_SHORT).show();
}
}
}
接收电量的变化
如果我们在使用阅读软件,可能是全屏阅读,这个时候用户就看不到剩余的电量,我们就可以为他们提供电量的信息。要想 做到这一点,我们需要接收一条电量变化的广播,然后获取百分比信息。
当系统的电量发生变化时, 该接收器会触发
/**
* 检测电量变化的广播接收器
*/
public class MyReceiver6 extends BroadcastReceiver {
public MyReceiver6() {
}
@Override
public void onReceive(Context context, Intent intent) {
//当前电量
int curr = intent.getIntExtra(BatteryManager.EXTRA_LEVEL, 0);
//总电量
int total = intent.getIntExtra(BatteryManager.EXTRA_SCALE, 1);
int percent = curr*100/total;
Toast.makeText(context, "当前电量为" + percent + "%", Toast.LENGTH_SHORT).show();
}
}
下面的方法会立即获取当前的电量
Intent batteryIntent = registerReceiver(null, intentFilter);
//当前电量
int curr = batteryIntent.getIntExtra(BatteryManager.EXTRA_LEVEL, 0);
//总电量
int total = batteryIntent.getIntExtra(BatteryManager.EXTRA_SCALE, 1);
int percent = curr*100/total;
Toast.makeText(this, "当前电量为" + percent + "%", Toast.LENGTH_SHORT).show();
最后提醒 :
When it runs on the main thread you should never perform long-running operations in it (there is a timeout of 10 seconds that the system allows before considering the receiver to be blocked and a candidate to be killed). You cannot launch a popup dialog in your implementation of onReceive().