【Android 基础知识】广播 Broadcast 基础

1、发送/接收临时广播

广播用于 Android 组件之间的灵活通信,与 Activity 的区别在于:

  1. Activity 只能一对一通信;Broadcast 可以一对多,一人发送广播,多人接收处理;
  2. 对于发送者来说,广播不需要考虑接收者有没有在工作,接收者在工作就接收广播,不在工作就丢弃广播;
  3. 对于接收者来说,会收到各式各样的广播,所以接收者要自行过滤符合条件的广播,才能进行解包处理。

与广播有关的方法主要有 3 个:

  • sendBroadcast:发送广播。
  • registerReceiver:注册接收器,一般在 onStart 或 onResume 方法中注册。
  • unregisterReceiver:注销接收器,一般在 onStop 或 onPause 方法中注销。

如果广播是在应用内使用,不需要跨进程,建议使用 LocalBroadcastManager 下的 registerReceiver 与 unregisterReceiver 方法,这样不但更有效率(不需要跨进程通信),还不用考虑广播开放造成的安全问题。

下面对广播的工作流程进行具体演示。现在 Fragment 内有一个 Spinner 下拉框,可选择背景颜色,一旦选中某个背景色,整个活动页面的背景色就换成新颜色。Fragment 内部发现选中颜色后,要发送一个背景色变更的广播,代码如下:

// 声明一个广播事件的标识串
public final static String EVENT = "com.example.senior.fragment.BroadcastFragment";
// 声明一个颜色名称数组
private String[] mColorNameArray = {"红色", "黄色", "绿色", "青色", "蓝色"};
// 声明一个颜色类型数组
private int[] mColorIdArray = {Color.RED, Color.YELLOW, Color.GREEN, Color.CYAN, Color.BLUE};
// 定义一个与下拉框配套的颜色选择监听器
class ColorSelectedListener implements OnItemSelectedListener {
    public void onItemSelected(AdapterView<?> arg0, View arg1, int arg2, long arg3) {
        if (!bFirst || mColorSeq != arg2) { // 如果要改变背景色
            mColorSeq = arg2;
            // 创建一个广播事件的意图
            Intent intent = new Intent(BroadcastFragment.EVENT);
            intent.putExtra("seq", arg2);
            intent.putExtra("color", mColorIdArray[arg2]);
            // 通过本地的广播管理器来发送广播
            LocalBroadcastManager.getInstance(mContext).sendBroadcast(intent);
        }
        bFirst = false;
    }

    public void onNothingSelected(AdapterView<?> arg0) {}
}

同时,Activity 代码要实现背景色变更的广播接收器。一旦接收到背景色变更的广播,就立即修改页面为最新的背景色,示例代码如下:

public void onStart() {
    super.onStart();
    initSpinner();
    // 创建一个背景色变更的广播接收器
    bgChangeReceiver = new BgChangeReceiver();
    // 创建一个意图过滤器,只处理指定事件来源的广播
    IntentFilter filter = new IntentFilter(BroadcastFragment.EVENT);
    // 注册广播接收器,注册之后才能正常接收广播
    LocalBroadcastManager.getInstance(mContext).registerReceiver(bgChangeReceiver, filter);
}

@Override
public void onStop() {
    // 注销广播接收器,注销之后就不再接收广播
    LocalBroadcastManager.getInstance(mContext).unregisterReceiver(bgChangeReceiver);
    super.onStop();
}

// 声明一个背景色变更的广播接收器
private BgChangeReceiver bgChangeReceiver;
// 定义一个广播接收器,用于处理背景色变更事件
private class BgChangeReceiver extends BroadcastReceiver {

    // 一旦接收到背景色变更的广播,马上触发接收器的onReceive方法
    public void onReceive(Context context, Intent intent) {
        if (intent != null) {
            // 从广播消息中取出最新的颜色序号
            mColorSeq = intent.getIntExtra("seq", 0);
            // 设置下拉框默认显示该序号项
            sp_bg.setSelection(mColorSeq);
        }
    }
}

在这里插入图片描述

2、定时器 AlarmManager

AlarmManager 是 Android 提供的一个全局定时器,利用系统闹钟定时发送广播。这样如果 App 提前注册闹钟的广播接收器,即使 App 退出了,只要定时到达,App 就会被唤醒响应广播事件。

下面具体演示下过程,首先在页面代码中通过 AlarmManager 设置闹钟:

public void onClick(View v) {
    if (v.getId() == R.id.btn_alarm) {
        // 创建一个广播事件的意图
        Intent intent = new Intent(ALARM_EVENT);
        // 创建一个用于广播的延迟意图
        PendingIntent pIntent = PendingIntent.getBroadcast(this, 0, intent,
                PendingIntent.FLAG_UPDATE_CURRENT);
        // 从系统服务中获取闹钟管理器
        AlarmManager alarmMgr = (AlarmManager) getSystemService(ALARM_SERVICE);
        Calendar calendar = Calendar.getInstance();
        calendar.setTimeInMillis(System.currentTimeMillis());
        // 给当前时间加上若干秒
        calendar.add(Calendar.SECOND, mDelay);
        // 开始设定闹钟,延迟若干秒后,携带延迟意图发送闹钟广播
        alarmMgr.set(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), pIntent);
        mDesc = DateUtil.getNowTime() + " 设置闹钟";
        tv_alarm.setText(mDesc);
    }
}

然后在页面代码中定义一个广播接收器 AlarmReceiver :

    // 声明一个闹钟广播事件的标识串
private String ALARM_EVENT = "com.example.senior.AlarmActivity.AlarmReceiver";
private static String mDesc = ""; // 闹钟时间到达的描述
private static boolean isArrived = false; // 闹钟时间是否到达

// 定义一个闹钟广播的接收器
public static class AlarmReceiver extends BroadcastReceiver {

    // 一旦接收到闹钟时间到达的广播,马上触发接收器的onReceive方法
    public void onReceive(Context context, Intent intent) {
        if (intent != null) {
            Log.d(TAG, "AlarmReceiver onReceive");
            if (tv_alarm != null && !isArrived) {
                isArrived = true;
                mDesc = String.format("%s\n%s 闹钟时间到达", mDesc, DateUtil.getNowTime());
                tv_alarm.setText(mDesc);
            }
        }
    }
}

接着打开 AndroidManifest.xml,在 application 节点下增加广播接收器的声明(Android 9.0 以前):

<receiver android:name=".AlarmActivity$AlarmReceiver" >
    <intent-filter>
        <action android:name="com.example.senior.AlarmActivity.AlarmReceiver" />
    </intent-filter>
</receiver>

Android 9.0 开始,需要在代码里声明(动态注册):

// 适配Android9.0开始
@Override
public void onStart() {
    super.onStart();
    // 从Android9.0开始,系统不再支持静态广播,应用广播只能通过动态注册
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
        // 创建一个闹钟的广播接收器
        alarmReceiver = new AlarmReceiver();
        // 创建一个意图过滤器,只处理指定事件来源的广播
        IntentFilter filter = new IntentFilter(ALARM_EVENT);
        // 注册广播接收器,注册之后才能正常接收广播
        registerReceiver(alarmReceiver, filter);
    }
}

@Override
public void onStop() {
    super.onStop();
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
        // 注销广播接收器,注销之后就不再接收广播
        unregisterReceiver(alarmReceiver);
    }
}

在这里插入图片描述

  • PendingIntent 的意思是延迟的意图,只要不是立即传递的消息,都要用 PendingIntent,PendingIntent 调用了 getBroadcast 方法,表示这次携带的消息用于发送广播。
  • AlarmManager 的 set 方法用于设置一次性定时器,alarmMgr.set(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), pIntent);该方法的第一个参数表示定时器类型(一般是 AlarmManager.RTC_WAKEUP,表示定时器即使在睡眠状态也会启动),第二个参数表示任务的执行时间,第三个参数表示携带消息的延迟任务(getBroadcast 返回的 PendingIntent 对象)。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

玳宸

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值