You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PeriodicWorkRequest执行过频:设置1.5小时周期却每15分钟运行

问题:PeriodicWorkRequest 设置90分钟更新间隔,实际却每15分钟执行一次

我尝试实现一个每1.5小时(90分钟)更新天气数据的Worker,使用PeriodicWorkRequestBuilder设置了时间参数,但Logcat显示Worker每15分钟就执行一次。相关代码如下:

主Activity中创建WorkRequest的代码

@RequiresApi(Build.VERSION_CODES.O)
override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    binding = ActivityMainBinding.inflate(layoutInflater)
    setContentView(binding.root)

    val workRequest = PeriodicWorkRequestBuilder<WeatherUpdateWorker>(
            repeatInterval = 90,
            repeatIntervalTimeUnit = TimeUnit.MINUTES,
        ).setBackoffCriteria(
            backoffPolicy = BackoffPolicy.LINEAR,
            duration = Duration.ofSeconds(15)
        )
            .build()

        WorkManager.getInstance(applicationContext).enqueueUniquePeriodicWork(
            "WeatherUpdateWork",
            ExistingPeriodicWorkPolicy.KEEP,
            workRequest
        )
}

WeatherUpdateWorker代码

@HiltWorker
class WeatherUpdateWorker @AssistedInject constructor(
    private val api: WeatherService,
    @Assisted val context: Context,
    @Assisted workerParameters: WorkerParameters,
    private val viewModel: WeatherViewModel
): CoroutineWorker(context, workerParameters) {
    override suspend fun doWork(): Result {

        try {
            val response = api.getWeather()
            viewModel.setWeatherResults(response)

            val currentTime = System.currentTimeMillis()
            saveLastExecutionTime(currentTime)

            Log.d("WeatherWorker", "Success, ${currentTime}")
            return Result.success()
        } catch (e: Exception) {
            Log.d("WeatherWorker", "Error")
            return Result.retry()
        }
    }

    private fun saveLastExecutionTime(currentTime: Long) {
        val sharedPreferences = context.getSharedPreferences("weather_prefs", Context.MODE_PRIVATE)
        sharedPreferences.edit().putLong("last_execution_time", currentTime).apply()
    }
}

WorkerFactory代码

@HiltAndroidApp
class Application : Application(), Configuration.Provider {

    @Inject
    lateinit var workerFactory: CustomWorkerFactory

    override fun getWorkManagerConfiguration() =
        Configuration.Builder()
            .setMinimumLoggingLevel(Log.DEBUG)
            .setWorkerFactory(workerFactory)
            .build()

}

class CustomWorkerFactory @Inject constructor(private val api: WeatherService, private val viewModel: WeatherViewModel): WorkerFactory() {
    override fun createWorker(
        appContext: Context,
        workerClassName: String,
        workerParameters: WorkerParameters
    ): ListenableWorker? = WeatherUpdateWorker(api, appContext, workerParameters, viewModel)
}

解决方案

1. 排查Worker执行失败导致的重试

先查看Logcat中的WeatherWorker日志,如果频繁出现Error,说明doWork()方法持续抛出异常,返回Result.retry()后,WorkManager会按照退避策略不断重试:

  • 检查api.getWeather()的网络请求是否正常:确认网络权限配置正确、接口地址/参数无误、服务器返回正常。
  • 移除Worker中的ViewModel依赖:ViewModel是绑定UI组件生命周期的,Worker作为后台任务持有ViewModel会导致生命周期不匹配,极易引发异常。建议Worker直接将数据存入本地存储(如SharedPreferences、Room),再由UI层读取展示。

2. 替换已存在的旧WorkRequest

如果之前创建过15分钟间隔的WorkRequest,使用ExistingPeriodicWorkPolicy.KEEP会保留旧任务,不会替换为新的90分钟间隔配置。将策略改为REPLACE,确保新配置生效:

WorkManager.getInstance(applicationContext).enqueueUniquePeriodicWork(
    "WeatherUpdateWork",
    ExistingPeriodicWorkPolicy.REPLACE, // 替换旧任务
    workRequest
)

3. 修复Worker的ViewModel依赖问题

修改Worker,去掉ViewModel注入,直接处理数据存储:

@HiltWorker
class WeatherUpdateWorker @AssistedInject constructor(
    private val api: WeatherService,
    @Assisted val context: Context,
    @Assisted workerParameters: WorkerParameters
): CoroutineWorker(context, workerParameters) {
    override suspend fun doWork(): Result {
        return try {
            val response = api.getWeather()
            // 将天气数据存入SharedPreferences
            saveWeatherData(response)
            
            val currentTime = System.currentTimeMillis()
            saveLastExecutionTime(currentTime)

            Log.d("WeatherWorker", "Success, ${currentTime}")
            Result.success()
        } catch (e: Exception) {
            Log.e("WeatherWorker", "执行失败", e) // 打印完整异常信息,方便排查
            Result.retry()
        }
    }

    private fun saveWeatherData(response: WeatherResponse) {
        val sharedPreferences = context.getSharedPreferences("weather_prefs", Context.MODE_PRIVATE)
        val gson = Gson()
        val json = gson.toJson(response)
        sharedPreferences.edit().putString("weather_data", json).apply()
    }

    private fun saveLastExecutionTime(currentTime: Long) {
        val sharedPreferences = context.getSharedPreferences("weather_prefs", Context.MODE_PRIVATE)
        sharedPreferences.edit().putLong("last_execution_time", currentTime).apply()
    }
}

同时更新CustomWorkerFactory,移除ViewModel参数:

class CustomWorkerFactory @Inject constructor(private val api: WeatherService): WorkerFactory() {
    override fun createWorker(
        appContext: Context,
        workerClassName: String,
        workerParameters: WorkerParameters
    ): ListenableWorker? = WeatherUpdateWorker(api, appContext, workerParameters)
}

4. 显式配置flexInterval(可选)

当repeatInterval >= 15分钟时,WorkManager默认的flexInterval为15分钟,这意味着Worker会在每个90分钟周期的最后15分钟窗口内执行。如果需要更精确的执行窗口控制,可以显式设置flexInterval:

val workRequest = PeriodicWorkRequestBuilder<WeatherUpdateWorker>(
    repeatInterval = 90,
    repeatIntervalTimeUnit = TimeUnit.MINUTES,
    flexInterval = 10, // 自定义flex间隔为10分钟
    flexIntervalTimeUnit = TimeUnit.MINUTES
).setBackoffCriteria(
    backoffPolicy = BackoffPolicy.LINEAR,
    duration = Duration.ofSeconds(15)
).build()

内容的提问来源于stack exchange,提问作者James Taufa

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.17 07:39:52