Android N 7.0中BroadcastReceiver广播收发实现咨询
看起来你已经在搭建基于AlarmManager触发广播的定时推送功能了,针对Android 7.0+的环境,我给你补全和优化整个实现流程:
一、补全并优化广播发送的PendingIntent创建代码
你的createEventPushPendingIntent方法还未完成,这里补充完整并适配高版本系统要求:
private fun createEventPushPendingIntent(event: EntityObject): PendingIntent { val intent = Intent(ctx, EventScheduleBroadcastReceiver::class.java) .putExtra(EXTRA_EVENT_INFO, EventInfo(event)) // Android 12+ 强制要求指定PendingIntent的可变/不可变标记 val flags = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { PendingIntent.FLAG_IMMUTABLE // 不需要修改Intent内容时用这个更安全 } else { PendingIntent.FLAG_UPDATE_CURRENT // 低版本用这个更新已有Intent的Extra } // 用事件唯一ID作为requestCode,避免不同事件的PendingIntent被覆盖 return PendingIntent.getBroadcast( ctx, event.id.hashCode(), intent, flags ) }
二、实现BroadcastReceiver接收类
接下来需要编写对应的广播接收器,处理接收到的事件逻辑:
class EventScheduleBroadcastReceiver : BroadcastReceiver() { override fun onReceive(context: Context?, intent: Intent?) { intent?.let { // 获取传递的EventInfo(注意EventInfo必须实现Parcelable接口) val eventInfo = it.getParcelableExtra<EventInfo>(EXTRA_EVENT_INFO) eventInfo?.let { info -> // 这里写你接收到广播后的业务逻辑,比如弹出通知 showEventNotification(context, info) } } } private fun showEventNotification(context: Context?, eventInfo: EventInfo) { context ?: return val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager // Android 8.0+ 需要创建通知渠道 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { val channel = NotificationChannel( "EVENT_REMINDER_CHANNEL", "事件提醒", NotificationManager.IMPORTANCE_DEFAULT ).apply { description = "定时事件的通知提醒渠道" } notificationManager.createNotificationChannel(channel) } val notification = NotificationCompat.Builder(context, "EVENT_REMINDER_CHANNEL") .setSmallIcon(R.drawable.ic_event_reminder) .setContentTitle(eventInfo.title) .setContentText(eventInfo.content) .setPriority(NotificationCompat.PRIORITY_DEFAULT) .build() notificationManager.notify(eventInfo.id.hashCode(), notification) } }
三、关键依赖:让EventInfo支持Intent传递
因为你要把EventInfo通过Intent传递,必须让它实现Parcelable接口,用Kotlin的话可以借助@Parcelize简化实现:
// 首先确保build.gradle(app)里添加了parcelize插件 // plugins { // id 'kotlin-parcelize' // } @Parcelize data class EventInfo( val id: Int, val title: String, val content: String, // 其他你需要的字段 ) : Parcelable { // 从EntityObject转换的构造方法 constructor(event: EntityObject) : this( event.id, event.title, event.content // 对应EntityObject的字段逐一赋值 ) }
四、Android 7.0+的核心适配要点
- 显式广播合法性:你用的是指定了组件类的显式Intent,不受Android 7.0开始的隐式广播限制,静态注册完全可行。
- AlarmManager触发准确性:Android 19(KitKat)之后,
AlarmManager.set()会被系统批量调度以省电,若需要精确触发,建议按版本适配:
override fun addToSchedule(event: EntityObject) { val pendingIntent = createEventPushPendingIntent(event) val triggerTime = computeTimeToPush(event) when { Build.VERSION.SDK_INT >= Build.VERSION_CODES.M -> { // Doze模式下也能触发 alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, triggerTime, pendingIntent) } Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT -> { // 精确触发但不支持Doze alarmManager.setExact(AlarmManager.RTC_WAKEUP, triggerTime, pendingIntent) } else -> { alarmManager.set(AlarmManager.RTC_WAKEUP, triggerTime, pendingIntent) } } }
- 静态注册接收器:在
AndroidManifest.xml中注册你的广播接收器:
<receiver android:name=".EventScheduleBroadcastReceiver" android:exported="false" /> <!-- 不需要外部应用触发时设为false更安全 -->
五、测试注意事项
- 测试Doze模式下的触发:可以用adb命令强制设备进入Doze模式,验证广播是否能正常触发:
adb shell dumpsys deviceidle force-idle - 避免PendingIntent覆盖:确保每个事件的
requestCode唯一(比如用事件ID的哈希值),防止不同事件的定时任务被互相覆盖。
内容的提问来源于stack exchange,提问作者P. Ilyin
相关产品推荐
相关产品推荐

