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

Android:如何在idle_maintenance模式下执行发送追踪信息的任务?

How to Execute Tasks During Doze's idle_maintenance Window

Hey there! Let's break down how to get your tracking tasks running smoothly during the idle_maintenance window in Doze mode, since it sounds like your app's getting blocked right now.

First, a quick recap: When Android enters idle (Doze) mode, it restricts most app activity to save battery. The idle_maintenance window is a short, periodic interval where the system lifts these restrictions to let apps complete critical tasks. If your app is blocked here, it’s likely because you’re using traditional background task APIs that don’t account for Doze’s constraints.

The most reliable tools for this are built to work with Doze out of the box:

  • WorkManager: The official Jetpack library for background tasks. It automatically handles Doze, App Standby, and other system restrictions—this is the easiest, most recommended choice.
  • AlarmManager: Use this if you need precise, one-time or periodic scheduling (but WorkManager is preferred for most cases, as it abstracts away low-level details).

WorkManager lets you define tasks with constraints that ensure they run only during idle_maintenance windows.

Step 1: Add Dependencies

Add this to your app-level build.gradle (module level):

dependencies {
    def work_version = "2.8.1"
    implementation "androidx.work:work-runtime-ktx:$work_version"
}

Step 2: Create a Worker Class

This class handles your tracking task. We’ll use CoroutineWorker to run the task in a background coroutine (no manual thread management needed):

import android.content.Context
import androidx.work.CoroutineWorker
import androidx.work.WorkerParameters
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext

class TrackingWorker(context: Context, params: WorkerParameters) : CoroutineWorker(context, params) {
    override suspend fun doWork(): Result {
        return try {
            // Run tracking logic on a background dispatcher to avoid blocking
            withContext(Dispatchers.IO) {
                sendTrackingData()
            }
            Result.success() // Mark task as completed
        } catch (e: Exception) {
            // Retry if the task fails (adjust retry policy as needed)
            Result.retry()
        }
    }

    private fun sendTrackingData() {
        // Replace this with your actual tracking logic (e.g., API call)
        println("Sending tracking data during idle_maintenance window...")
        // Example: val response = apiClient.postTrackingEvent(trackingPayload)
        // if (!response.isSuccessful) throw Exception("Failed to send tracking data")
    }
}

Step 3: Schedule the Task with Constraints

Set up constraints to ensure the task runs only when the device is in an idle state (including idle_maintenance):

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import androidx.work.Constraints
import androidx.work.PeriodicWorkRequestBuilder
import androidx.work.WorkManager
import java.util.concurrent.TimeUnit

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        // Define constraints: Only run when device is idle
        val idleConstraints = Constraints.Builder()
            .setRequiresDeviceIdle(true) // Critical: Triggers during idle_maintenance
            .setRequiresBatteryNotLow(true) // Optional: Avoid running on low battery
            .build()

        // Create a periodic task (e.g., run every 12 hours)
        val trackingRequest = PeriodicWorkRequestBuilder<TrackingWorker>(12, TimeUnit.HOURS)
            .setConstraints(idleConstraints)
            .build()

        // Enqueue the task with WorkManager
        WorkManager.getInstance(this).enqueue(trackingRequest)
    }
}

Example 2: Using AlarmManager (For Precise Scheduling)

If you need a task to run at an exact time (even in Doze), use setExactAndAllowWhileIdle() (available on Android 6.0+):

Step 1: Create a Broadcast Receiver

This receiver triggers your tracking task:

import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import kotlin.concurrent.thread

class TrackingAlarmReceiver : BroadcastReceiver() {
    override fun onReceive(context: Context?, intent: Intent?) {
        // Run the task in a background thread (onReceive runs on the main thread!)
        thread {
            sendTrackingData(context)
        }
    }

    private fun sendTrackingData(context: Context?) {
        // Replace with your tracking logic
        println("Sending tracking data via AlarmManager during idle_maintenance...")
    }
}

Step 2: Register the Receiver

Add this to your AndroidManifest.xml:

<receiver android:name=".TrackingAlarmReceiver" />

Step 3: Schedule the Alarm

Set up the alarm to run even in Doze mode:

import android.app.AlarmManager
import android.app.PendingIntent
import android.content.Context
import android.content.Intent
import android.os.Build
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import java.util.concurrent.TimeUnit

class MainActivity : AppCompatActivity() {
    private val ALARM_REQUEST_CODE = 1001

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val alarmManager = getSystemService(Context.ALARM_SERVICE) as AlarmManager
        val intent = Intent(this, TrackingAlarmReceiver::class.java)
        val pendingIntent = PendingIntent.getBroadcast(
            this,
            ALARM_REQUEST_CODE,
            intent,
            PendingIntent.FLAG_UPDATE_CURRENT or if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) PendingIntent.FLAG_IMMUTABLE else 0
        )

        // Schedule the alarm to run in 12 hours, even in Doze
        val triggerTime = System.currentTimeMillis() + TimeUnit.HOURS.toMillis(12)
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            alarmManager.setExactAndAllowWhileIdle(
                AlarmManager.RTC_WAKEUP,
                triggerTime,
                pendingIntent
            )
        } else {
            // Compatibility for older Android versions
            alarmManager.setExact(AlarmManager.RTC_WAKEUP, triggerTime, pendingIntent)
        }
    }
}

Key Notes to Avoid Blocking

  • Never run long tasks on the main thread: Use coroutines (WorkManager) or background threads (AlarmReceiver) to prevent ANRs.
  • Keep tasks short: The idle_maintenance window is brief (usually a few minutes), so focus on critical operations like sending tracking data, not heavy processing.
  • Test Doze mode: Use these ADB commands to simulate Doze:
    • adb shell dumpsys deviceidle force-idle (force device into Doze)
    • adb shell dumpsys deviceidle step (trigger the next idle_maintenance window)

内容的提问来源于stack exchange,提问作者Adan Condori C.

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.25 04:23:05