Android应用离线倒计时恢复生命值功能实现求助
解决Android生命值系统后台计时与离线恢复问题
核心思路
先解决问题B(离线时间计算),这是基础——不要依赖实时倒计时,改用「时间戳差值计算」,再用WorkManager处理后台定时更新,解决问题A。
问题B:应用关闭后恢复生命值的解决方案
不管应用是否运行,核心是记录「最后一次生命值变更的时间戳」,每次需要更新生命值时(应用启动、后台任务触发),计算当前时间与上次时间的差值,算出应恢复的生命值:
- 存储关键数据:用
SharedPreferences存两个值- 当前生命值
current_lives - 最后一次生命值更新的时间戳
last_update_timestamp(毫秒级)
- 当前生命值
- 计算逻辑:
- 获取当前时间戳,算出与上次更新的时间差
- 按每小时1条计算可恢复数量,不超过上限10条
- 更新生命值和时间戳
代码实现(存储与计算工具类)
object LiveDataManager { private const val PREF_NAME = "LiveSystemPrefs" private const val KEY_CURRENT_LIVES = "current_lives" private const val KEY_LAST_UPDATE = "last_update_timestamp" private const val MAX_LIVES = 10 private const val RECOVERY_INTERVAL = 60 * 60 * 1000L // 1小时 // 更新生命值(核心计算逻辑) fun updateLives(context: Context): Int { val prefs = context.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE) val currentLives = prefs.getInt(KEY_CURRENT_LIVES, 10) // 默认满生命值 val lastUpdate = prefs.getLong(KEY_LAST_UPDATE, System.currentTimeMillis()) val now = System.currentTimeMillis() val timeDiff = now - lastUpdate // 计算可恢复的生命值 val recoverableLives = (timeDiff / RECOVERY_INTERVAL).toInt() val newLives = min(currentLives + recoverableLives, MAX_LIVES) // 只有生命值变化时才更新存储 if (newLives != currentLives) { prefs.edit() .putInt(KEY_CURRENT_LIVES, newLives) .putLong(KEY_LAST_UPDATE, now) .apply() } return newLives } // 扣除生命值(操作失误时调用) fun deductLife(context: Context): Int { val prefs = context.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE) val currentLives = prefs.getInt(KEY_CURRENT_LIVES, 10) val newLives = max(currentLives - 1, 0) prefs.edit() .putInt(KEY_CURRENT_LIVES, newLives) .putLong(KEY_LAST_UPDATE, System.currentTimeMillis()) // 扣除后更新时间戳 .apply() return newLives } // 获取当前生命值 fun getCurrentLives(context: Context): Int { return context.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE) .getInt(KEY_CURRENT_LIVES, 10) } }
问题A:后台倒计时不运行的解决方案
放弃普通Service,改用WorkManager——这是Google官方推荐的后台任务调度组件,适配Android 8+的后台限制,即使应用在后台或重启,也能可靠触发任务。
步骤1:实现Worker类
class LiveRecoveryWorker( context: Context, params: WorkerParameters ) : CoroutineWorker(context, params) { override suspend fun doWork(): Result { // 执行生命值更新逻辑 LiveDataManager.updateLives(applicationContext) // 可选:更新后发送通知提示用户 return Result.success() } }
步骤2:启动周期性任务
在Application类的onCreate中初始化任务,确保唯一且持续运行:
class MyApp : Application() { override fun onCreate() { super.onCreate() // 每小时执行一次生命值更新任务 val recoveryWork = PeriodicWorkRequestBuilder<LiveRecoveryWorker>(1, TimeUnit.HOURS) .setConstraints(Constraints.Builder() .setRequiredNetworkType(NetworkType.NOT_REQUIRED) // 无需网络 .build()) .build() // 确保任务唯一,避免重复创建 WorkManager.getInstance(this).enqueueUniquePeriodicWork( "LiveRecoveryTask", ExistingPeriodicWorkPolicy.KEEP, recoveryWork ) } }
步骤3:Activity中使用
进入页面时先更新生命值,确保UI显示最新状态:
class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) // 页面启动时更新生命值 val currentLives = LiveDataManager.updateLives(this) // 更新UI显示currentLives // 操作失误扣除生命值示例 btnDeductLife.setOnClickListener { val newLives = LiveDataManager.deductLife(this) // 更新UI显示newLives } } }
关键说明
- 为什么不用Service?
Android 8+对后台Service有严格限制,后台Service极易被系统回收,导致计时中断。WorkManager会根据系统资源状态调度任务,可靠性远高于普通Service。 - 前台实时倒计时怎么处理?
如果需要在前台显示「距离下次恢复的剩余时间」,可以用CountDownTimer结合LiveData,仅在Activity前台时运行即可——后台的恢复逻辑由WorkManager和时间戳保证,无需前台持续计时。
内容的提问来源于stack exchange,提问作者GIANT
相关产品推荐
相关产品推荐

