Member-only story
Compose Performance Part 7: Images at Scale with Coil 3 — Why AsyncImage Is More Expensive Than You Think, Bitmap Memory Math (Width × Height × 4 Bytes), Proper Image Sizing Before Bitmap Decode, Memory Cache vs Disk Cache Configuration, Crossfade Performance Costs, Placeholder Strategies, Sub-Sampling for Large Images, Pre-Caching Strategies, Coil 3 Multiplatform Configuration, and the Patterns That Make Image-Heavy Lists Scroll as Smoothly as Text-Only Ones
You did everything right in Part 6. Your LazyColumn has keys, contentType, stable items, deferred animation reads, the works. Your list scrolls smoothly with text-only items. Then you add AsyncImage to each row, and suddenly the list stutters every time the user scrolls. Frame drops appear during fling. Memory usage climbs. On lower-end devices, the list becomes unusable.
Images are where many Android apps quietly leak performance. The framework makes loading images look easy — AsyncImage(model = url, contentDescription = null) and you're done — but that simplicity hides a series of performance landmines: bitmap memory cost, cache misses, decode-on-main-thread, oversized bitmaps for tiny views, crossfade animations during scroll, and placeholder thrashing. Get them wrong and the smoothest LazyColumn in the world feels janky.










