How to Implement Image and GIF Caching for Mobile Fitness Apps: A Technical Guide
Implement a three-tier caching strategy—combining in-memory LRU caches, persistent disk storage, and HTTP cache-control headers—to deliver 180×180 exercise thumbnails and GIFs instantly while minimizing mobile data usage.
Mobile fitness applications displaying exercise libraries require instant access to thousands of visual assets. The hasaneyldrm/exercises-dataset repository provides 1,324 pre-scaled thumbnails and matching GIFs with deterministic URLs, making it an ideal dataset for implementing robust image and GIF caching in mobile fitness apps.
Three-Layer Caching Architecture
Implementing image and GIF caching for mobile fitness apps requires coordinating three distinct storage layers to eliminate network latency when displaying content from the images/ and videos/ directories.
Memory Cache Layer
The memory cache delivers fastest access for assets currently visible on screen. Implement platform-specific LRU caches—LruCache on Android, NSCache on iOS, or React Native FastImage's built-in memory cache—to store recently decoded bitmaps. This layer eliminates disk I/O overhead when users scroll through exercise lists populated from data/exercises.json.
Disk Cache Layer
The disk cache provides persistent storage across app launches, reducing repeated downloads of the repository's assets. Store downloaded files in the app's cache directory with size-limited eviction policies. Libraries like Glide (Android), Coil (Android/Kotlin), SDWebImage (iOS), and react-native-fast-image automatically manage disk caches using the repository's deterministic filenames (<id>-<media_id>.jpg).
Network Optimization Layer
Minimize payload by serving the repository's pre-scaled 180×180 assets with HTTP Cache-Control and ETag headers. Configure your CDN to return 304 Not Modified responses when assets haven't changed, leveraging the created_at timestamp in data/exercises.json for cache-busting strategies. Refer to setup.html in the repository for backend configuration examples.
Implementation Workflow
Follow this sequence when integrating with the hasaneyldrm/exercises-dataset repository to load metadata and cache assets efficiently.
Load Exercise Metadata
First, retrieve the exercise list from data/exercises.json. Each record contains image (thumbnail path) and gif_url (animation path) fields pointing to assets in the images/ and videos/ folders:
{
"id": "0001",
"name": "3/4 Sit-Up",
"image": "images/0001-2gPfomN.jpg",
"gif_url": "videos/0001-2gPfomN.gif",
"created_at": "2023-01-15T10:30:00Z",
"media_id": "2gPfomN"
}
Resolve full URLs by prepending your CDN base URL (e.g., https://cdn.example.com/) to these relative paths.
React Native Implementation
Use react-native-fast-image to automatically handle memory and disk caching with immutable cache control:
import FastImage from 'react-native-fast-image';
const CDN = 'https://cdn.example.com/';
export const ExerciseCard = ({ ex }) => {
const thumbUrl = `${CDN}${ex.image}`;
const gifUrl = `${CDN}${ex.gif_url}`;
return (
<FastImage
style={{ width: 180, height: 180, borderRadius: 8 }}
source={{
uri: thumbUrl,
priority: FastImage.priority.normal,
cache: FastImage.cacheControl.immutable,
}}
placeholder={require('../assets/placeholder.png')}
onLoadEnd={() => {
FastImage.preload([{ uri: gifUrl }]);
}}
/>
);
};
Android Implementation with Coil
For Kotlin Android apps, implement Coil to cache thumbnails and preload GIFs from the repository:
import coil.load
import coil.request.CachePolicy
import coil.transform.CircleCropTransformation
fun loadExerciseImage(imageView: ImageView, exercise: Exercise) {
val baseUrl = "https://cdn.example.com/"
val thumbUrl = baseUrl + exercise.image
val gifUrl = baseUrl + exercise.gif_url
imageView.load(thumbUrl) {
placeholder(R.drawable.placeholder)
crossfade(true)
diskCachePolicy(CachePolicy.ENABLED)
memoryCachePolicy(CachePolicy.ENABLED)
}
imageView.context.imageLoader.enqueue(
ImageRequest.Builder(imageView.context)
.data(gifUrl)
.diskCachePolicy(CachePolicy.ENABLED)
.memoryCachePolicy(CachePolicy.ENABLED)
.build()
)
}
iOS Implementation with SDWebImage
Configure SDWebImage to cache assets from the repository's images/ and videos/ directories:
import SDWebImage
func setExerciseImage(_ imageView: UIImageView, exercise: Exercise) {
let base = "https://cdn.example.com/"
let thumbURL = URL(string: base + exercise.image)!
let gifURL = URL(string: base + exercise.gif_url)!
imageView.sd_setImage(
with: thumbURL,
placeholderImage: UIImage(named: "placeholder"),
options: [.cacheMemoryOnly, .refreshCached]
)
SDWebImagePrefetcher.shared.prefetchURLs([gifURL])
}
Flutter Implementation
Use cached_network_image to cache 180×180 thumbnails from the dataset:
import 'package:flutter/material.dart';
import 'package:cached_network_image/cached_network_image.dart';
class ExerciseTile extends StatelessWidget {
final Map ex;
const ExerciseTile(this.ex, {Key? key}) : super(key: key);
static const cdn = 'https://cdn.example.com/';
@override
Widget build(BuildContext context) {
final thumb = cdn + ex['image'];
final gif = cdn + ex['gif_url'];
return CachedNetworkImage(
imageUrl: thumb,
placeholder: (_, __) => const SizedBox(
width: 180,
height: 180,
child: Center(child: CircularProgressIndicator()),
),
imageBuilder: (_, img) => Image(image: img, width: 180, height: 180),
fadeOutDuration: const Duration(milliseconds: 300),
fadeInDuration: const Duration(milliseconds: 300),
);
}
}
Cache Invalidation Strategies
When updating exercise content from hasaneyldrm/exercises-dataset, implement cache invalidation using the deterministic filename structure. Since assets follow the pattern <id>-<media_id>.jpg and <id>-<media_id>.gif as defined in data/exercises.json, updating the media_id or created_at fields automatically busts existing caches by generating new URLs.
Validate incoming data against data/exercises.schema.json before caching to ensure compatibility. For manual cache clearing, purge disk caches when releasing major app updates or when the README.md indicates breaking changes to the asset structure.
Summary
- Three-tier architecture: Combine memory LRU caches, persistent disk storage in the app's cache directory, and HTTP cache-control headers for instant 180×180 thumbnail display.
- Deterministic URLs: Leverage the repository's
<id>-<media_id>naming convention inimages/andvideos/directories for reliable cache keys that auto-bust when content updates. - Progressive loading: Display static thumbnails immediately while preloading GIFs from the
videos/folder in the background to ensure smooth animations. - Schema validation: Use
data/exercises.schema.jsonto validate metadata before caching, ensuring field integrity forimageandgif_urlpaths.
Frequently Asked Questions
How much storage should I allocate for caching the exercises dataset?
Allocate 50-100MB for LRU disk caching when using the hasaneyldrm/exercises-dataset. With 1,324 exercises averaging 10-15KB per thumbnail and 200-500KB per GIF, a complete local cache requires approximately 300-700MB. Configure your caching library to evict least-recently-used assets when approaching these limits, prioritizing retention of frequently accessed items from the images/ directory.
Should GIFs be cached differently than static thumbnails?
Yes. Cache static thumbnails (from the repository's images/ directory) aggressively in both memory and disk since they appear frequently in exercise lists. Cache GIFs (from the videos/ directory) primarily on disk due to their larger file size, keeping only the currently playing animation in memory to prevent memory pressure during workouts.
How do I handle cache updates when the dataset changes?
Monitor the media_id or created_at fields in data/exercises.json. When either value changes, the <id>-<media_id>.jpg filename changes automatically, treating the asset as new content that bypasses existing cache entries. Configure your backend to serve appropriate HTTP headers based on the created_at timestamp to enable 304 Not Modified validation for unchanged assets.
Can I use this caching strategy with offline-first fitness apps?
Absolutely. Pre-populate the disk cache by downloading all 1,324 assets referenced in data/exercises.json during app installation or when Wi-Fi is available. Store files from the images/ and videos/ directories in persistent storage rather than temporary cache directories, ensuring exercise demonstrations remain accessible without network connectivity.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →