BroadcastReceiver也是Android系统的四大组件之一,是一种全局的监听器,用于监听系统全局的广播消息。那么问题来了,什么是广播。Android作为一种手机系统,在执行很多事情的时候都会以数据形式传输信息出去,例如在手机开机、电池电量低、屏幕锁定等等情况下都会发送,这种数据信息就是广播,能够收到这种信息的就是广播接收器,这些信息由系统发送,就是系统广播,广播也可以通过普通应用程序发送,就是普通广播。而对于广播的接受者也非随便一个广播接受器都可以接收,需要相应的Action(Intent数据传输中用来标记接收组件,广播接收器也是一样的)。
由于其监听的全局性,它可以方便地完成各组件的通信。作为一种监听器当然是用来在触发时执行某些操作,生命周期?它没有,做了该做的事就没了。
同Service一样BroadcastReceiver也没有用户界面(监听器要界面干什么呢),它的创建和Service一样,需要手动创建自定义广播接收器并继承BroadcastReceiver类,并注册。一般eclipse会提示重写onReceiver()方法(如果创建好类并继承了BroadcastReceiver但是没有先在配置文件中注册就不会提示,只是报错)。如果OnReceiver方法不能在10秒内执行完成,android会认为该程序无响应,弹出ANR(Application NoResponse)的对话框。所以BroadcastReceiver是不可以用来执行耗时操作的。(Service才是耗时操作的首选)
BroadcastReceiver注册有静态注册和动态注册两种。静态注册:在配置文件中添加<receiver>标签设定 <intent-filter>元素中的<action>绑定标签。动态注册调用Context的registerReceiver方法,参数为Receiver对象与InterFilter对象,这种方法注册甚至可以不在配置文件中注册name属性,取消注册的方法为unregisterReceiver()。
发送广播的方式有三种,无论是系统广播还是普通广播,在不同程序中定义的接收器都能收到(只要Action匹配)。
sendBroadcast:发送无序广播,默认的广播机制,所有能与Intent的Action匹配的Receiver都会被触发,理论上所有Receiver同时去接受广播,消息传递的效率高,但是接收者不能将处理结果传递给下一个接收者,并且无法终止Broadcast Intent的传播。
sendOrderBroadcast:广播接收器根据优先级依次接收广播,优先级越大越早收到广播(优先级通过<intent-filter>中的priority属性设置,取值范围-1000到1000,值越大优先级越高,也可以调用IntentFilter对象的setPriority()进行设置)。
在优先级高的广播接收器中可以加入额外的数据再传递给下一个(优先级较低的)广播接收器,方法为setResultExtras(Bundle),也可以中断广播传递,比其优先级低的接收器将无法收到广播,方法为abortBradcast()。
sendStickyBroadcast:发送粘性广播,该广播在发出后会滞留一段时间,这样如果发送广播后没有匹配广播接收器,等有了相应的广播接收器后,该广播接受器仍能收到广播。(之上两种广播均为即时广播)这种广播需要申请发送粘性广播的权限。
以下做一个简单的实现来测试广播和广播接收器的收发机制,当然,我们这里只是通过简单的表达方法来确认接收器是否收到广播。布局文件如下
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="sendBroadcast"
android:text="发送无序广播" />
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="setReceiver"
android:text="取消Second广播接收器的注册" />
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="sendOrderedBroadcast"
android:text="发送有序广播" />
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="sendStickyBroadcast"
android:text="发送粘性广播" />
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="setThird"
android:text="注册ThirdBroadcastReceiver" />
</LinearLayout>
MainActivity类文件如下
import android.app.Activity;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
public class MainActivity extends Activity {
private SecondReceiver second;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
second = new SecondReceiver();
setSecondReceiver();
}
// 应用程序发出一条带有特定Action的广播
public void sendBroadcast(View v) {
Intent intent = new Intent();
intent.putExtra("data", "Message");
intent.setAction("come");
sendBroadcast(intent);
}
public void setReceiver(View v) {
Button btn = (Button) v;
String name = btn.getText().toString();
if (name.equals("取消Second广播接收器的注册")) {
// 取消广播接受器注册
unregisterReceiver(second);
btn.setText("设置Second广播接收器的注册");
} else {
setSecondReceiver();
btn.setText("取消Second广播接收器的注册");
}
}
// 发送有序广播
public void sendOrderedBroadcast(View v) {
Intent intent = new Intent("come");
intent.putExtra("data", "Message");
sendOrderedBroadcast(intent, null);
}
public void setSecondReceiver() {
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction("come");
intentFilter.setPriority(10);
// 动态注册广播接收器
registerReceiver(second, intentFilter);
}
// 发送粘性广播,可先发广播后注册
public void sendStickyBroadcast(View v) {
Intent intent = new Intent("come3");
sendStickyBroadcast(intent);
}
public void setThird(View v){
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction("come3");
registerReceiver(new ThirdReceiver(), intentFilter);
}
}
第一个广播接收器
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.widget.Toast;
public class FirstBroadcastReseiver extends BroadcastReceiver{
//收到匹配的广播后执行的逻辑代码,它的生命周期很短,不能执行耗时操作
@Override
public void onReceive(Context arg0, Intent arg1) {
String data = arg1.getStringExtra("data");
Toast.makeText(arg0, "FirstBroadcastReceiver-"+data, Toast.LENGTH_SHORT).show();
//终止广播继续传递,比它优先级的低的接收器将无法收到广播
//abortBroadcast();
//向下一个接收器增加广播内容
Bundle bundle = new Bundle();
bundle.putString("data+", "Add Message");
setResultExtras(bundle);
}
}
第二个广播接收器
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.widget.Toast;
public class SecondReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context arg0, Intent arg1) {
String data = arg1.getStringExtra("data");
Bundle bundle = getResultExtras(true);
String data2 = bundle.getString("data+");
Toast.makeText(arg0, "SecondReceiver-" + data + "+" + data2,
Toast.LENGTH_SHORT).show();
}
}
第三个广播接收器
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.widget.Toast;
public class ThirdReceiver extends BroadcastReceiver{
@Override
public void onReceive(Context context, Intent intent) {
Toast.makeText(context, "ThirdReceiver", Toast.LENGTH_SHORT).show();
}
}
配置文件如下
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.briup.broadcastreceiver"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="16"
android:targetSdkVersion="24" />
<uses-permission android:name="android.permission.BROADCAST_STICKY" />
<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=".FirstBroadcastReseiver" >
<intent-filter android:priority="100" >
<action android:name="come" />
</intent-filter>
</receiver>
</application>
</manifest>
第一个广播接收器是通过静态注册的,第二三个广播接收器是通过动态注册的。效果如下
运行测试后,发送无序广播由于Toast的延迟第二个广播接收器会先弹出Toast,但是实际它们是同时收到广播的;我们在MainActivity的onCreate方法中为第二个广播接收器进行了动态注册,当我们取消它的注册后,它就无法收到广播了;发送有序广播,由于第一个接收器优先级大于第二个接收器,所以总是先弹出第一个接收器中的Toast,而且由于我们在第一个广播接受器中增加了广播内容,所以第二个接收器消息比第一个要长;先点击发送粘性广播,没有反应,当我们点击为第三个接收器注册的按钮时就弹出了第三个接收器中的Toast。