diligence is your life password, can translate your grand epic poem.勤奋是你生命的密码,能译出你一部壮丽的诗。
本讲内容: Broadcast Receiver 广播接收者的使用
一、Broadcast Receiver的介绍
记得我们上学的时候,每个班级的教室里都会装有一个喇叭,这些喇叭都是接入到学校的广播室的,一旦有什么重要的通知,就会播放一条广播来告知全校的师生。譬如:当电池电量改变时,系统会产生一条广播,接收到这条广播就能在电量低时告知用户及时保存进度,等等。
二、Android中的广播分为两种类型:标准广播和有序广播。
1、标准广播是是一种完全异步执行的广播,在广播发出之后,所有的广播接收器几乎都会在同一时刻接收收到这条广播消息,因此它们之间没有任何先后顺序可言。这种广播的效率会比较高,但同时也意味着它是无法被截断的。
2、有序广播则是一种同步执行的广播,在广播发出之后,同一时刻只会一个广播接收器能够收到这条广播消息,当这个广播接收器中的逻辑执行完毕后,广播才会继续传递。所以此时的广播接收器是有先后顺序的,优先级高的广播接收器就可以先收到广播消息,并且前面的广播接收器还可以截断正在传递的广播,这样后面的广播接收器就无法收到广播消息了。
三、注册广播的方式有两种,在代码中注册和在AndroidManifest.xml中注册,其中前者称为动态注册,后者称为静态注册。
四、如何创建一个广播接收器?
只需要新建一个类,让它继承自BroadcastReceiver,并重写父类的onReceive()方法,这样当有广播到来时,onReceive()方法就会得到执行,具体的逻辑就可以在这个方法中处理。
示例一:接收系统广播(譬如:动态注册实现网络变化)
下面是MainActivity.java主界面文件:
public class MainActivity extends Activity {
private IntentFilter intentFilter;
private NetworkChangeReceiver networkChangeReceiver;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
intentFilter = new IntentFilter();
// 添加一个值为android.net.conn.CONNECTIVITY_CHANGE的action,因为当网络状态发生变化时,系统会发出一条值为
// android.net.conn.CONNECTIVITY_CHANGE的广播。即我们的广播接收器想要监听什么广播,就在这里添加相应的action就行了。
intentFilter.addAction("android.net.conn.CONNECTIVITY_CHANGE");
// 创建一个广播接收器
networkChangeReceiver = new NetworkChangeReceiver();
// 动态注册
registerReceiver(networkChangeReceiver, intentFilter);
}
protected void onDestroy() {
super.onDestroy();
// 取消注册
unregisterReceiver(networkChangeReceiver);
}
class NetworkChangeReceiver extends BroadcastReceiver {
public void onReceive(Context context, Intent intent) {
//ConnectivityManager主要管理和网络连接相关的操作,然后通过它的getNetworkInfo()方法得到NetworkInfo实例,
//NetworkInfo类包含了对wifi和mobile两种网络模式连接的
ConnectivityManager connectionManager = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo mobileInfo = connectionManager.getNetworkInfo(connectionManager.TYPE_MOBILE);
NetworkInfo wifiInfo = connectionManager.getNetworkInfo(connectionManager.TYPE_WIFI);
if (mobileInfo.isConnected()||wifiInfo.isConnected()) {
Toast.makeText(context, "WIFI或GPRS网络已连接", Toast.LENGTH_LONG).show();
}else{
Toast.makeText(context, "网络没有连接", Toast.LENGTH_LONG).show();
// 跳转到无线网络设置界面
//startActivity(new Intent(android.provider.Settings.ACTION_WIRELESS_SETTINGS));
// 跳转到无限wifi网络设置界面
//startActivity(new Intent(android.provider.Settings.ACTION_WIFI_SETTINGS));
}
}
}
}
在AndroidManifest.xml中注册(查询系统的网络状态就要声明权限)
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
示例二:接收系统广播(譬如:静态注册实现开机启动)
动态注册的广播接收器可以自由地控制注册与注销,在灵活性方面有很大的优势,但是它也存在一个缺点,即必须要在程序启动后才能接收到广播,因为注册的逻辑是写在onCreate()方法中的。
重启开机会执行onReceive()方法
下面是MainActivity.java主界面文件:
public class MainActivity extends Activity {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
}
这里不再使用内部类的方式来定义广播接收器,因为需要在AndroidManifest.xml中将这个广播接收器注册。
下面是BootCompleteReceiver.java文件:
public class BootCompleteReceiver extends BroadcastReceiver{
public void onReceive(Context context, Intent intent) {
Toast.makeText(context, "Boot Complete", Toast.LENGTH_LONG).show();
}
}
在AndroidManifest.xml文件(要声明监听系统开机广播权限)
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.broadcastreceiver"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="21" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name=".MainActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<receiver android:name=".BootCompleteReceiver">
<intent-filter >
<action android:name="android.intent.action.BOOT_COMPLETED"/>
</intent-filter>
</receiver>
</application>
</manifest>
五、发送自定义广播(之前我们学习了通过广播接收器接收系统广播)
示例三:(发送标准广播)
下面是MainActivity.java主界面文件:
public class MainActivity extends Activity {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.activity_main);
Button button=(Button) findViewById(R.id.button);
button.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
//自定义广播,这样所有监听com.example.broadcastreceiver.MY_BROADCAT这条广播的广播接收器就会收到消息
Intent intent=new Intent("com.example.broadcastreceiver.MY_BROADCAT");
sendBroadcast(intent);
}
});
}
}
下面是MyBroadcastReceiver.java文件:
public class MyBroadcastReceiver extends BroadcastReceiver {
public void onReceive(Context context, Intent intent) {
Toast.makeText(context, "received in MyBroadcastReceived",Toast.LENGTH_LONG).show();
}
}
下面是AndroidManifest.xml文件
<receiver android:name=".MyBroadcastReceiver" >
<intent-filter>
<action android:name="com.example.broadcastreceiver.MY_BROADCAT" />
</intent-filter>
</receiver>
示例四:(发送标准广播)
广播是一种可以跨进程的通信方式,从接收系统广播可以看出来,因此在我们应用程序内发出的广播,其它的应用程序也可以收到的。
新建一个新的项目,在这个项目定义一个广播AnotherBroadcastReceiver
下面是AnotherBroadcastReceiver.java文件:
public class AnotherBroadcastReceiver extends BroadcastReceiver{
public void onReceive(Context context, Intent intent) {
Toast.makeText(context, "received in AnotherBroadcastReceiver", Toast.LENGTH_LONG).show();
}
}
下面是AndroidManifest.xml文件
<receiver android:name=".AnotherBroadcastReceiver" >
<intent-filter>
<action android:name="com.example.broadcastreceiver.MY_BROADCAT" />
</intent-filter>
</receiver>
示例五:(有序广播)
下面是MainActivity.java主界面文件:
public class MainActivity extends Activity {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.activity_main);
Button button=(Button) findViewById(R.id.button);
button.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
//自定义广播,这样所有监听com.example.broadcastreceiver.MY_BROADCAT这条广播的广播接收器就会收到消息
Intent intent=new Intent("com.example.broadcastreceiver.MY_BROADCAT");
//有序广播两个参数,第二个参数是一个权限相关的字符串,传入null就行了
sendOrderedBroadcast(intent, null);
}
});
}
}
注意:使用sendOrderedBroadcast方法发送有序广播时,需要一个权限参数,如果为null则表示不要求接收者声明指定的权限,如果不为null,则表示接收者若要接收此广播,需声明指定权限。这样做是从安全角度考虑的,例如系统的短信就是有序广播的形式,一个应用可能是具有拦截垃圾短信的功能,当短信到来时它可以先接受到短信广播,必要时终止广播传递,这样的软件就必须声明接收短信的权限。
<receiver android:name=".MyBroadcastReceiver" >
<intent-filter android:priority="100">
<action android:name="com.example.broadcastreceiver.MY_BROADCAT" />
</intent-filter>
</receiver>
android:priority 属性给广播接收器设置优先级,这里设置为100,以保证它一定会在AnotherBroadcastReceiver之前收到广播。下面是MyBroadcastReceiver.java文件:
public class MyBroadcastReceiver extends BroadcastReceiver {
public void onReceive(Context context, Intent intent) {
Toast.makeText(context, "receiver in MyBroadcastReceiver", Toast.LENGTH_LONG).show();
//将这条广播截断,后面的广播接收器将无法收到
abortBroadcast();
}
}
示例六:使用本地广播
前面我们发送和接收的广播全部都属于系统全局广播,即发出的广播可以被其它任务应用程序接收到,并且我们也可以接收任何应用程序的广播。这样很容易引起安全性问题,譬如其它程序不断地向我们的广播接收器发送各种垃圾广播。为了解决广播的安全性问题,Android引入了一套本地广播机制,使用这个机制发出的广播只能够在应用程序的内部进行传递,并且广播也只能接收来自本应用程序发出的广播。
本地广播使用了一个LocalBroadcastManager来对广播进行管理,并提供了发送广播和注册广播接收器的方法。
下面是MainActivity.java主界面文件:
public class MainActivity extends Activity {
private IntentFilter intentFilter;
private LocalBroadcastReceiver localReceiver;
private LocalBroadcastManager localBroadcastManager;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.activity_main);
//获取实例
localBroadcastManager=LocalBroadcastManager.getInstance(this);
Button button=(Button) findViewById(R.id.button);
button.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
//自定义广播,这样所有监听com.example.broadcastreceiver.LOCAL_BROADCAT这条广播的广播接收器就会收到消息
Intent intent=new Intent("com.example.broadcastreceiver.LOCAL_BROADCAST");
//发送本地广播
localBroadcastManager.sendBroadcast(intent);
}
});
//注册广播
intentFilter=new IntentFilter();
intentFilter.addAction("com.example.broadcastreceiver.LOCAL_BROADCAST");
localReceiver=new LocalBroadcastReceiver();
localBroadcastManager.registerReceiver(localReceiver, intentFilter);
}
protected void onDestroy() {
super.onDestroy();
localBroadcastManager.unregisterReceiver(localReceiver);
}
class LocalBroadcastReceiver extends BroadcastReceiver{
public void onReceive(Context context, Intent intent) {
Toast.makeText(context, "receiver local Broadcast", Toast.LENGTH_LONG).show();
}
}
}
可以尝试示例四中其它应用程序无法收到这条com.example.broadcastreceiver.LOCAL_BROADCAST广播注意:本地广播是无法通过静态注册的方式来接收的,因为静态注册主要就是为了让程序在未启动的情况下也能收到广播,而发送本地广播时,我们的程序肯定是已经启动了。