fix: 息屏后MQTT断连导致无法收到通知
添加前台服务+WakeLock保活MQTT连接,请求电池优化白名单绕过Doze限制, AlarmManager每5分钟健康检查断连自动重连。 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,85 @@
|
||||
package com.xiaoqu.watch.service
|
||||
|
||||
import android.app.AlarmManager
|
||||
import android.app.PendingIntent
|
||||
import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.os.Build
|
||||
import android.os.SystemClock
|
||||
import com.xiaoqu.watch.service.manager.MqttManager
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
|
||||
/**
|
||||
* MQTT 连接健康检查广播接收器
|
||||
*
|
||||
* 通过 AlarmManager.setExactAndAllowWhileIdle() 定期触发,
|
||||
* 在 Doze 模式的维护窗口中检查 MQTT 连接状态,断连则重连。
|
||||
* 同时确保 MqttService 前台服务存活。
|
||||
*/
|
||||
@AndroidEntryPoint
|
||||
class MqttAlarmReceiver : BroadcastReceiver() {
|
||||
|
||||
companion object {
|
||||
/** 检查间隔:5 分钟(Doze 维护窗口至少 10 分钟,5 分钟能抓到窗口期) */
|
||||
private const val CHECK_INTERVAL_MS = 5 * 60 * 1000L
|
||||
|
||||
/** 启动定时健康检查 */
|
||||
fun schedule(context: Context) {
|
||||
val alarmManager = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager
|
||||
val intent = Intent(context, MqttAlarmReceiver::class.java)
|
||||
val pendingIntent = PendingIntent.getBroadcast(
|
||||
context, 0, intent,
|
||||
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
|
||||
)
|
||||
|
||||
// setExactAndAllowWhileIdle: Doze 模式下也能触发
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
alarmManager.setExactAndAllowWhileIdle(
|
||||
AlarmManager.ELAPSED_REALTIME_WAKEUP,
|
||||
SystemClock.elapsedRealtime() + CHECK_INTERVAL_MS,
|
||||
pendingIntent
|
||||
)
|
||||
} else {
|
||||
alarmManager.setExact(
|
||||
AlarmManager.ELAPSED_REALTIME_WAKEUP,
|
||||
SystemClock.elapsedRealtime() + CHECK_INTERVAL_MS,
|
||||
pendingIntent
|
||||
)
|
||||
}
|
||||
Timber.d("MqttAlarm: 已设置 ${CHECK_INTERVAL_MS / 1000}s 后检查")
|
||||
}
|
||||
|
||||
/** 取消定时检查 */
|
||||
fun cancel(context: Context) {
|
||||
val alarmManager = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager
|
||||
val intent = Intent(context, MqttAlarmReceiver::class.java)
|
||||
val pendingIntent = PendingIntent.getBroadcast(
|
||||
context, 0, intent,
|
||||
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
|
||||
)
|
||||
alarmManager.cancel(pendingIntent)
|
||||
Timber.d("MqttAlarm: 已取消定时检查")
|
||||
}
|
||||
}
|
||||
|
||||
@Inject lateinit var mqttManager: MqttManager
|
||||
|
||||
override fun onReceive(context: Context, intent: Intent) {
|
||||
Timber.d("MqttAlarm: 健康检查触发, isConnected=${mqttManager.isConnected}")
|
||||
|
||||
// 确保前台服务在运行
|
||||
MqttService.start(context)
|
||||
|
||||
// MQTT 断连则重连
|
||||
if (!mqttManager.isConnected) {
|
||||
Timber.w("MqttAlarm: 连接已断开,触发重连")
|
||||
mqttManager.connect()
|
||||
}
|
||||
|
||||
// 重新设置下一次闹钟(setExactAndAllowWhileIdle 是一次性的)
|
||||
schedule(context)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user