基于AlarmManager的追踪应用:设备休眠时GPS关闭,如何维持定位更新?
Hey there! Let’s break down how to keep your GPS running and get periodic location updates even when your Android device is asleep. I’ve wrestled with this exact issue for tracking apps before, so here’s the practical, actionable stuff you need:
一、First, understand why this happens
When your device enters Doze Mode (deep sleep), Android aggressively restricts background services, network access, and GPS wake-ups to save battery. Even your AlarmManager calls get delayed in this state—so just pairing it with a regular background service won’t cut it.
二、Step-by-step solutions
1. Switch to a Foreground Service
Foreground services are marked as "high-priority" by the system, which means they’re less likely to be killed, and they maintain access to GPS even when the device is asleep. The catch? You have to show a persistent notification in the status bar (required by Android to keep users informed).
Here’s a quick code snippet to set this up:
class LocationTrackingService : Service() { override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { // Create a basic notification for the foreground service val notification = NotificationCompat.Builder(this, "TRACKING_CHANNEL_ID") .setContentTitle("Location Tracking Active") .setContentText("Your app is updating location periodically") .setSmallIcon(R.drawable.ic_tracking_icon) .build() // Start the service in foreground mode startForeground(1, notification) // Kick off your GPS location update logic here startLocationUpdates() return START_STICKY // Restart service if it gets killed } private fun startLocationUpdates() { // Implement your FusedLocationProviderClient or LocationManager logic here } }
Don’t forget: On Android 12+, you need the POST_NOTIFICATIONS permission (request it at runtime) and declare the FOREGROUND_SERVICE permission in your manifest.
2. Replace AlarmManager with WorkManager
WorkManager is Google’s recommended tool for scheduling background tasks—it’s designed to handle Doze Mode and App Standby automatically. For periodic location updates, use PeriodicWorkRequest (note: the minimum interval is 15 minutes, enforced by Android for battery conservation).
Example setup:
// Define a Worker class to handle location fetching class LocationTrackingWorker(appContext: Context, workerParams: WorkerParameters) : Worker(appContext, workerParams) { override fun doWork(): Result { // Fetch location here (you might want to trigger the foreground service temporarily) fetchAndReportLocation() return Result.success() } } // Schedule the periodic work val trackingWork = PeriodicWorkRequestBuilder<LocationTrackingWorker>(15, TimeUnit.MINUTES) .setConstraints(Constraints.Builder() .setRequiredNetworkType(NetworkType.CONNECTED) // Optional: if you need to send data .build()) .build() WorkManager.getInstance(context).enqueueUniquePeriodicWork( "LOCATION_TRACKING_TASK", ExistingPeriodicWorkPolicy.REPLACE, trackingWork )
3. Request the right permissions (critical for Android 10+)
On Android 10 (API 29) and above, you need the ACCESS_BACKGROUND_LOCATION permission to fetch location when the app isn’t in the foreground. For Android 12+, you also need to make sure users grant the "Allow all the time" location permission (not just "While using the app").
Add these to your AndroidManifest.xml:
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> <uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" /> <uses-permission android:name="android.permission.FOREGROUND_SERVICE" /> <uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
4. Use WakeLock sparingly
If you need to temporarily wake the CPU to fetch a location update (without keeping the screen on), you can use a PowerManager.WakeLock. But be careful—this drains battery, so only use it when absolutely necessary, and always release it after you’re done.
Example:
val powerManager = getSystemService(POWER_SERVICE) as PowerManager val wakeLock = powerManager.newWakeLock( PowerManager.PARTIAL_WAKE_LOCK, "TrackingApp::LocationWakeLock" ) // Acquire the wake lock for up to 10 minutes (adjust as needed) wakeLock.acquire(10 * 60 * 1000L) // Fetch your location... // Release the wake lock immediately after wakeLock.release()
5. Leverage Doze Mode maintenance windows
If your app doesn’t need ultra-frequent updates, you can rely on Doze Mode’s regular maintenance windows—this is when the system wakes up the device to handle background tasks. WorkManager automatically schedules tasks to run during these windows, so it’s a battery-friendly way to get updates without fighting the system.
三、Pro tips for testing & optimization
- Always test on a real device—emulators don’t replicate Doze Mode behavior accurately.
- Avoid overly frequent updates (stick to the 15-minute minimum if possible) to avoid being flagged as a battery hog.
- On Android 13+, guide users to select "Allow all the time" for location permissions—otherwise, background location access will be blocked even with a foreground service.
内容的提问来源于stack exchange,提问作者traj

