目录
(1)一个广播存在多个接收器,这些接收器需要排队收听广播,这意味着该广播是条有序广播。
1.收发标准广播
(1)发送广播
只需要创建意图再调用sendBroadcast方法发送广播即可。
public class BroadStandardActivity extends AppCompatActivity implements View.OnClickListener {
// 这是广播的动作名称,发送广播和接收广播都以它作为接头暗号
private final static String STANDARD_ACTION = "com.example.chapter04.standard";
private TextView tv_standard; // 声明一个文本视图对象
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_broad_standard);
tv_standard = findViewById(R.id.tv_standard);
tv_standard.setText(mDesc);
findViewById(R.id.btn_send_standard).setOnClickListener(this);
}
@Override
public void onClick(View v) {
if (v.getId() == R.id.btn_send_standard) {
Intent intent = new Intent(STANDARD_ACTION); // 创建指定动作的意图
sendBroadcast(intent); // 发送标准广播
}
}
}
(2)定义广播接收器
接收器主要规定两个事情,一个是接收什么样的广播,另一个接收广播后要做什么。Android提供了抽象之后的接收器基类BroadcastReceiver,开发者自定义的接收器都从BroadcastReceiver派生而来,新定义的接收器需要重写onReceive方法,方法内部先判断当前广播是否符合待接收广播名称,校验通过后在开展后续业务逻辑。
private String mDesc = "这里查看标准广播的收听信息";
// 定义一个标准广播的接收器
private class StandardReceiver extends BroadcastReceiver {
// 一旦接收到标准广播,马上触发接收器的onReceive方法
@Override
public void onReceive(Context context, Intent intent) {
// 广播意图非空,且接头暗号正确
if (intent != null && intent.getAction().equals(STANDARD_ACTION)) {
mDesc = String.format("%s\n%s 收到一个标准广播", mDesc, DateUtil.getNowTime());
tv_standard.setText(mDesc);
}
}
(3)开关广播接收器
private StandardReceiver standardReceiver; // 声明一个标准广播的接收器实例
@Override
protected void onStart() {
super.onStart();
standardReceiver = new StandardReceiver(); // 创建一个标准广播的接收器
// 创建一个意图过滤器,只处理STANDARD_ACTION的广播
IntentFilter filter = new IntentFilter(STANDARD_ACTION);
registerReceiver(standardReceiver, filter); // 注册接收器,注册之后才能正常接收广播
}
@Override
protected void onStop() {
super.onStop();
unregisterReceiver(standardReceiver); // 注销接收器,注销之后就不再接收广播
}
2.收发有序广播
(1)一个广播存在多个接收器,这些接收器需要排队收听广播,这意味着该广播是条有序广播。
(2)先收到广播的接收器A,既可以让其他接收器继续收听广播,也可以中断广播不让其它接收器收听。
有序广播的收发有以下几个步骤:
1.发送广播时注明是有序广播
之前发送标准广播用到了sendBroadcast方法,可是该方法发出来的广播是无序的,只有调用sendOrderedBroadcast才能发送有序广播,发送代码示例如下:
Intent intent = new Intent(ORDER_ACTION); // 创建一个指定动作的意图
sendOrderedBroadcast(intent, null); // 发送有序广播
2.定义有序广播接收器
接收器的定义代码基本不变,也要从BroadcastReceiver继承而来,唯一的区别是有序广播的接收器允许中断广播。倘若在接收器内部调用abortBroadcast方法,就会中断有序广播,使得后面的接收器不能再接收广播。
private OrderAReceiver orderAReceiver; // 声明有序广播接收器A的实例
// 定义一个有序广播的接收器A
private class OrderAReceiver extends BroadcastReceiver {
// 一旦接收到有序广播,马上触发接收器的onReceive方法
@Override
public void onReceive(Context context, Intent intent) {
if (intent != null && intent.getAction().equals(ORDER_ACTION)) {
String desc = String.format("%s%s 接收器A收到一个有序广播\n",
tv_order.getText().toString(), DateUtil.getNowTime());
tv_order.setText(desc);
if (ck_abort.isChecked()) {
abortBroadcast(); // 中断广播,此时后面的接收器无法收到该广播
}
}
}
}
3.注册有序广播的多个接收器
接收器的注册操作同样调用registerReceiver方法,为了给接收器排队,还需调用意图过滤器的setPriority方法设置优先级,优先级越大的接收器,越先收到有序广播。如果不设置优先级,或者两个接收器优先级相等,那么越早注册的接收器,会越先收到有序广播。
// 多个接收器处理有序广播的顺序规则为:
// 1、优先级越大的接收器,越早收到有序广播;
// 2、优先级相同的时候,越早注册的接收器越早收到有序广播
orderAReceiver = new OrderAReceiver(); // 创建一个有序广播的接收器A
// 创建一个意图过滤器A,只处理ORDER_ACTION的广播
IntentFilter filterA = new IntentFilter(ORDER_ACTION);
filterA.setPriority(8); // 设置过滤器A的优先级,数值越大优先级越高
registerReceiver(orderAReceiver, filterA); // 注册接收器A,注册之后才能正常接收广播
3.收发静态广播
在AndroidManifest.xml中注册接收器,该方法被称作静态注册,在代码中注册接收器,该方式被成为动态注册。创建一个类来做广播接收处理,同时在AndroidManifest.xml中添加以下代码
public class ShockReceiver extends BroadcastReceiver {
private static final String TAG = "ShockReceiver";
// 静态注册时候的action、发送广播时的action、接收广播时的action,三者需要保持一致
public static final String SHOCK_ACTION = "com.example.chapter04.shock";
@Override
public void onReceive(Context context, Intent intent) {
Log.d(TAG, "onReceive");
if (intent.getAction().equals(ShockReceiver.SHOCK_ACTION)){
// 从系统服务中获取震动管理器
Vibrator vb = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
vb.vibrate(500); // 命令震动器吱吱个若干秒,这里的500表示500毫秒
}
}
}
<receiver
android:name=".receiver.ShockReceiver"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="com.example.chapter04.shock" />
</intent-filter>
</receiver>
发送广播
// Android8.0之后删除了大部分静态注册,防止退出App后仍在接收广播,
// 为了让应用能够继续接收静态广播,需要给静态注册的广播指定包名。
String receiverPath = "com.example.chapter04.receiver.ShockReceiver";
Intent intent = new Intent(ShockReceiver.SHOCK_ACTION); // 创建一个指定动作的意图
// 发送静态广播之时,需要通过setComponent方法指定接收器的完整路径
ComponentName componentName = new ComponentName(this, receiverPath);
intent.setComponent(componentName); // 设置意图的组件信息
sendBroadcast(intent); // 发送静态广播
Toast.makeText(this, "已发送震动广播", Toast.LENGTH_SHORT).show();
4.定时管理器 AlarmManager
// 从系统服务中获取闹钟管理器
AlarmManager alarmMgr = (AlarmManager) getSystemService(ALARM_SERVICE);
常见方法说明:
set:设置一次性定时器,第一个参数为定时器类型,通常填alarmMgr .RTC_WAKEUP;第二个参数为期望的执行时刻(单位为毫秒),第三个参数为待执行的延迟意图(PendingIntent类型)
setAndAllowWhiteIdle:设置一次性定时器,参数说明同set方法,不同之处在于:即使设备处于空闲状态,也会保证执行定时器。因为从Android 6.0中,set方法在暗屏不保证发送广播,必须调用setAndAllowWhileIdle方法才能保证发送广播。
setRepeating:设置重复定时器,第一个参数为定时器类型;第二个参数为首次执行时间,第三个参数为下次执行的间隔时间,第四个参数为待执行的延迟意图,然而setRepeating方法不保证按时发送广播,只能通过setAndAllowWhiteIdle方法间接实现重复定时功能。
cancel:取消指定延时意图的定时器
PendingIntent和Intent区别:
(1)PendingIntent代表延迟的意图,它指向的组件不会马上被激活;而Intent代表实时的意图,一旦被启动,它指向的组件会被马上激活。
(2)PendingIntent是一类消息的组合,不但包含目标的Intent对象,还包含请求代码,请求方式等信息。
(3)PendingIntent对象在创建时便已知晓将要用于活动还是广播,例如调用getActivity方法得到的是活动跳转的延迟意图,调用getBroadcast方法得到的是广播发送的延迟意图。
1.定义定时器的广播接收器
闹钟广播的接收器采用动态注册方式,它的实现途径与标准广播类似,都要从BroadcastReceiver派生新的接收器,并重写onReceive方法
// 声明一个闹钟广播事件的标识串
private String ALARM_ACTION = "com.example.chapter04.alarm";
private String mDesc = ""; // 闹钟时间到达的描述
// 定义一个闹钟广播的接收器
public class AlarmReceiver extends BroadcastReceiver {
// 一旦接收到闹钟时间到达的广播,马上触发接收器的onReceive方法
@Override
public void onReceive(Context context, Intent intent) {
if (intent != null) {
mDesc = String.format("%s\n%s 闹钟时间到达", mDesc, DateUtil.getNowTime());
tv_alarm.setText(mDesc);
// 从系统服务中获取震动管理器
Vibrator vb = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
vb.vibrate(500); // 命令震动器吱吱个若干秒
if (ck_repeate.isChecked()) { // 需要重复闹钟广播
sendAlarm(); // 发送闹钟广播
}
}
}
}
2.开关定时器的广播接收器
private AlarmReceiver alarmReceiver; // 声明一个闹钟的广播接收器
@Override
public void onStart() {
super.onStart();
alarmReceiver = new AlarmReceiver(); // 创建一个闹钟的广播接收器
// 创建一个意图过滤器,只处理指定事件来源的广播
IntentFilter filter = new IntentFilter(ALARM_ACTION);
registerReceiver(alarmReceiver, filter); // 注册接收器,注册之后才能正常接收广播
}
@Override
public void onStop() {
super.onStop();
unregisterReceiver(alarmReceiver); // 注销接收器,注销之后就不再接收广播
}
3.设置定时器的播放规则
// 发送闹钟广播
private void sendAlarm() {
Intent intent = new Intent(ALARM_ACTION); // 创建一个广播事件的意图
// 从Android12开始,必须添加 FLAG_IMMUTABLE 或者 FLAG_MUTABLE
// 创建一个用于广播的延迟意图
PendingIntent pIntent = PendingIntent.getBroadcast(this, 0,
intent, PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_UPDATE_CURRENT);
// 从系统服务中获取闹钟管理器
AlarmManager alarmMgr = (AlarmManager) getSystemService(ALARM_SERVICE);
long delayTime = System.currentTimeMillis() + mDelay*1000; // 给当前时间加上若干秒
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
// 允许在空闲时发送广播,Android6.0之后新增的方法
alarmMgr.setAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, delayTime, pIntent);
} else {
// 设置一次性闹钟,延迟若干秒后,携带延迟意图发送闹钟广播(但Android6.0之后,set方法在暗屏时不保证发送广播,必须调用setAndAllowWhileIdle方法)
alarmMgr.set(AlarmManager.RTC_WAKEUP, delayTime, pIntent);
}
// // 设置重复闹钟,每隔一定间隔就发送闹钟广播(但从Android4.4开始,setRepeating方法不保证按时发送广播)
// alarmMgr.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(),
// mDelay*1000, pIntent);
}