We encounter this problem on nearly every other project: the app loads images one by one, memory grows until OOM. Or a softer scenario—users on iPhone 12 in Low Data Mode wait 4–6 seconds for the first image because the app downloads a 4K original instead of a preview. In our practice, a client complained about crashes when viewing a gallery of 200 photos. Android Profiler showed Bitmap allocation of 4, 8, 14, 23 MB… The typical root cause is missing parametric resize URLs and incorrect caching. We implement a combination: CDN resize + disk cache + BlurHash. Optimizing image loading in mobile apps requires a comprehensive approach.
What Problems Does Image Loading Optimization Solve?
Incorrect Image Size
The server delivers an original 2400×3200, but the ImageView is 80×80 dp. Glide, Kingfisher, or Coil downscale, but first those 29 MB arrive over the network and are decoded in memory. Parametric resize URLs (?w=160&h=160&fit=crop) solve the problem before loading. This reduces traffic by 30–50% and speeds up display.
Missing Disk Cache
By default, SDWebImage caches to disk, but if someone sets SDWebImageOptions.refreshCached for "freshness", every app launch reloads all images. On avatar screens, this means 20–30 extra network requests each time a screen opens. A proper cache limit (500 MB) lets images load once.
Sequential Instead of Parallel Loading
Custom implementations using URLSession.dataTask often create a queue where the next request starts only after the previous finishes. In a list of 10 items, you wait for the sum of all 10 RTTs instead of the maximum one.
OOM When Loading a Gallery
Pagination with a visibility window of ±2 pages, parametric URLs sized for the ImageView, and a decoded image cache limit of 20–100 MB fix the problem. In a carousel with 50+ images, use lazy loading and preload only the current and adjacent pages.
Why Is Image Loading Optimization Important?
Image loading optimization directly impacts user experience and app metrics. Slow loading causes up to 40% of drop-offs on mobile devices. Implementing the methods described above pays off through reduced CDN costs and higher user retention. In one project, we cut load time from 8 to 1.2 seconds, boosting conversion by 15%. Typical savings: 30–50% on CDN costs, and our optimization service starts at $500.
Why Use WebP?
WebP delivers 25–35% better compression than JPEG at the same visual quality. On Android, Glide supports WebP out of the box; on iOS, Kingfisher does via the .webpConversion flag. For maximum efficiency, pass the format parameter in the URL—?format=webp. This reduces traffic and speeds up loading, saving your image hosting budget.
How We Optimize Image Loading
Our approach to image loading optimization includes the following stack: on iOS—Kingfisher for Swift projects, SDWebImage for Obj-C legacy. Kingfisher is convenient with KFImage in SwiftUI and native @MainActor support. Key settings:
KingfisherManager.shared.cache.diskStorage.config.sizeLimit = 500 * 1024 * 1024 // 500 MB KingfisherManager.shared.cache.memoryStorage.config.totalCostLimit = 100 * 1024 * 1024 // 100 MB For progressive JPEG loading, use ImageDataProcessor with ProgressiveJPEGAddon. The user sees a blurred image immediately instead of a placeholder for 2 seconds.
On Android: Coil for Compose projects (native AsyncImage), Glide for View-based. Glide supports thumbnail(0.1f)—it loads 10% of the original size as a placeholder while the full version loads. This preview loads 10x faster than the full image. For WebP conversion on the server, Glide handles it natively; Coil requires SvgDecoder/VideoFrameDecoder via separate dependencies.
A mandatory pattern for both platforms: parametric URLs sized for the specific ImageView. If the backend is on Cloudinary or imgproxy, pass ?width={viewWidthDp * density}&format=webp&quality=80.
Placeholder Strategy
An empty gray rectangle is bad. BlurHash or ThumbHash is good. These are compact (20–30 bytes) hashes that render locally as a colored blurry preview before the real content loads. On iOS, use the BlurHash library; on Android, io.github.nicklockwood:thumbhash. The hash data comes with the API JSON response—zero network cost for the preview. BlurHash preview loads instantly compared to static placeholder.
Case Study: Carousel with 50 Images (From Our Practice)
A client implemented a UIScrollView with UIImageView via page control. When the screen opened, it loaded all 50 images at once. On slow 3G, the WKWebView crashed with OOM after 3–4 scrolls.
Solution: lazy loading via UIPageViewController with a visibility window of ±2 pages. An NSCache with a 20 MB limit for decoded images. The rest—only URLs in memory. Time to first interaction dropped from 8 to 1.2 seconds, and CDN costs decreased by 40%.
Comparison of Approaches
| Method | Traffic Savings | Load Time | Implementation Complexity |
|---|---|---|---|
| Server-side resize | 30–50% | -1.5 s | Low (change URL) |
| BlurHash | 0% (hash) | 1.5 s faster | Medium (add hash) |
| Disk cache 500 MB | Up to 80% on repeats | -0.7 s | Low (set cache limit) |
| Progressive JPEG | 0% | -0.3 s on preview | Medium (add processor) |
| Typical Mistake | Consequence | Fix |
|---|---|---|
| Loading original without resize | OOM, 4–6 s load | Parametric URL |
| No disk cache | Repeated requests | Set cache limit |
| Sequential loading | Summed wait time | Parallel loading |
Configuring Parametric URLs
For imgproxy, use format: /rs:fit:320:320/plain/https://example.com/image.jpg. Cloudinary: /c_fit,w_320,h_320/f_webp,q_80. Parameters must account for screen density.
Deliverables
- Audit of the current image loading scheme (network library, cache, sizes)
- Integration of Kingfisher/Glide/Coil with optimal settings
- Configuration of parametric resize URLs (CDN)
- Implementation of BlurHash or ThumbHash previews
- Optimization of pagination and lazy loading
- Testing on real devices under poor connection conditions
- Architecture documentation and support recommendations
- Training for your development team on maintaining the setup
Timelines
Auditing image loading and configuring the library: 1–3 days. If integration of CDN resize and BlurHash across the entire app is needed: 1 week. Cost is calculated individually.
We guarantee that after optimization, OOM will not recur, and load time will be cut at least in half. Our experience: over 10 years in mobile development, 40+ successful projects. With over a decade of expertise and 40+ projects delivered, we ensure measurable results. Get a consultation—we'll answer your questions and propose an improvement plan. Order an audit or contact us to start optimization.







