Caching Strategies
Why caching is central to mobile
Caching — keeping a local copy of data so you don’t refetch it — is one of the highest-impact mobile design tools. It makes the app feel instant, saves the user’s data and battery, reduces backend load, and enables offline use. Almost every performance win involves caching the right thing at the right level.
The cache hierarchy
Production apps use multiple cache levels, checked fastest-first:
- Memory cache — fastest, but small and lost when the app is killed. An LRU map of recently used objects/images.
- Disk cache — survives restarts; a database or file cache. Slower than memory, far faster than network.
- Network — the source of truth on the server; slowest, costs data.
Read order: memory → disk → network. Write order: when you fetch from network, populate disk and memory so next time it’s instant.
Cache-aside pattern
suspend fun getUser(id: String): User {
memoryCache[id]?.let { return it } // 1. memory
diskCache.get(id)?.let { memoryCache[id] = it; return it } // 2. disk
val user = api.getUser(id) // 3. network
diskCache.put(id, user); memoryCache[id] = user // populate caches
return user
}
Invalidation: the hard part
“There are only two hard things in computer science: cache invalidation and naming things.” Stale caches show wrong data. Strategies:
- Time-to-live (TTL) — data expires after N minutes.
- Event-based — clear/refresh when something changes (a push, a user edit).
- Validation — use HTTP
ETag/Last-Modifiedso the server returns “not changed” cheaply. - Manual — pull-to-refresh forces a fresh fetch.
Bounding caches (don’t get killed)
Memory caches must be size-bounded (LRU eviction) or the OS kills your app. Disk caches must be bounded too (max size, evict oldest) or you fill the user’s storage. Always cap your caches.
What to cache vs not
- Cache aggressively: images, feeds, profiles, reference data — things that don’t change every second.
- Cache carefully: rapidly changing data (prices, live scores) with short TTLs.
- Don’t cache: sensitive data in plain caches; security-critical state.
Common mistakes
- Unbounded memory/disk caches → out-of-memory or full storage.
- No invalidation → users see stale data.
- Caching sensitive data insecurely.
- Caching everything, including data that must always be live.
Summary: Layer caches memory → disk → network, reading fastest-first and populating on miss (cache-aside). Bound every cache with eviction, and invalidate with TTLs, events or validation (ETags). Cache aggressively for stable data, carefully for volatile data, and never cache secrets insecurely.