Battery & Network Optimization

📖 Concept

Battery optimization is critical for user retention. Android's battery management has become increasingly aggressive with each version. Senior engineers must design apps that work within these constraints.

Battery-draining operations:

  1. Wake locks — Keeping CPU/screen active. Use sparingly with proper timeouts.
  2. GPS polling — Location updates drain battery significantly. Use fused location provider with appropriate intervals.
  3. Network polling — Frequent network requests keep the radio active. Batch requests.
  4. Background services — Long-running services consume CPU. Use WorkManager.
  5. Alarms — Exact alarms prevent the device from entering Doze. Use inexact when possible.

Android power management features:

  • Doze mode (6.0+): When device is stationary and screen off, network/wake locks/alarms are deferred to maintenance windows.
  • App Standby Buckets (9.0+): Apps are ranked by usage frequency. Infrequently used apps get fewer resources.
  • Background execution limits (8.0+): Background services limited to ~10 minutes. Use Foreground Service or WorkManager.

Network optimization:

  • OkHttp connection pooling — Reuse TCP connections. Default: 5 connections, 5 min keepalive.
  • HTTP caching — Cache responses using Cache-Control headers. OkHttp supports this natively.
  • Compression — Use gzip for request/response bodies.
  • Batching — Combine multiple small requests into one batch request.
  • Prefetching — Load data before the user needs it, but intelligently (on WiFi, charged).

💻 Code Example

codeTap to expand ⛶
1// Network optimization with OkHttp
2@Module
3@InstallIn(SingletonComponent::class)
4object NetworkModule {
5 @Provides
6 @Singleton
7 fun provideOkHttpClient(@ApplicationContext context: Context): OkHttpClient {
8 val cacheDir = File(context.cacheDir, "http_cache")
9 val cache = Cache(cacheDir, 50L * 1024 * 1024) // 50MB cache
10
11 return OkHttpClient.Builder()
12 .cache(cache) // Enable HTTP caching
13 .addInterceptor(CacheInterceptor()) // Custom cache policy
14 .addNetworkInterceptor(HttpLoggingInterceptor())
15 .connectionPool(ConnectionPool(5, 5, TimeUnit.MINUTES))
16 .build()
17 }
18}
19
20// Cache interceptor — serve stale cache when offline
21class CacheInterceptor : Interceptor {
22 override fun intercept(chain: Interceptor.Chain): Response {
23 var request = chain.request()
24 // If offline, use cache (up to 7 days old)
25 if (!isNetworkAvailable()) {
26 request = request.newBuilder()
27 .cacheControl(CacheControl.Builder()
28 .maxStale(7, TimeUnit.DAYS)
29 .build())
30 .build()
31 }
32 return chain.proceed(request)
33 }
34}
35
36// Battery-aware sync scheduling
37fun scheduleSync(context: Context) {
38 val constraints = Constraints.Builder()
39 .setRequiredNetworkType(NetworkType.UNMETERED) // WiFi only
40 .setRequiresBatteryNotLow(true) // Don't sync on low battery
41 .setRequiresCharging(false) // But don't require charging
42 .build()
43
44 val syncWork = PeriodicWorkRequestBuilder<SyncWorker>(
45 1, TimeUnit.HOURS, // Repeat hourly
46 15, TimeUnit.MINUTES // Flex window
47 )
48 .setConstraints(constraints)
49 .setBackoffCriteria(BackoffPolicy.EXPONENTIAL, 10, TimeUnit.MINUTES)
50 .build()
51
52 WorkManager.getInstance(context)
53 .enqueueUniquePeriodicWork("sync", ExistingPeriodicWorkPolicy.KEEP, syncWork)
54}
55
56// Location optimization
57class LocationTracker @Inject constructor(
58 private val fusedClient: FusedLocationProviderClient
59) {
60 fun startTracking(priority: Priority): Flow<Location> = callbackFlow {
61 val request = LocationRequest.Builder(
62 if (priority == Priority.HIGH) Priority.PRIORITY_HIGH_ACCURACY
63 else Priority.PRIORITY_BALANCED_POWER_ACCURACY,
64 if (priority == Priority.HIGH) 5_000L else 30_000L // Interval ms
65 ).setMinUpdateDistanceMeters(
66 if (priority == Priority.HIGH) 10f else 100f
67 ).build()
68
69 val callback = object : LocationCallback() {
70 override fun onLocationResult(result: LocationResult) {
71 result.lastLocation?.let { trySend(it) }
72 }
73 }
74 fusedClient.requestLocationUpdates(request, callback, Looper.getMainLooper())
75 awaitClose { fusedClient.removeLocationUpdates(callback) }
76 }
77
78 enum class Priority { HIGH, LOW }
79}

🏋️ Practice Exercise

Practice:

  1. Implement HTTP caching with OkHttp and verify cached responses with stale-if-error
  2. Set up battery-aware WorkManager sync with appropriate constraints
  3. Profile your app's battery impact using Battery Historian
  4. Implement a smart prefetching strategy that loads data on WiFi only
  5. Measure your app's network traffic using Network Profiler and identify redundant calls

⚠️ Common Mistakes

  • Not using OkHttp's built-in cache — re-fetching data that hasn't changed wastes bandwidth and battery

  • Using exact alarms for non-time-critical work — exact alarms prevent Doze, use WorkManager instead

  • Polling with high frequency for location — use geofencing or significant motion triggers when possible

  • Not batching network requests — each request activates the radio, keeping it awake for 20-30 seconds

💼 Interview Questions

🎤 Mock Interview

Mock interview is powered by AI for Battery & Network Optimization. Login to unlock this feature.