flutter_app_cache_manager 1.0.1
flutter_app_cache_manager: ^1.0.1 copied to clipboard
A comprehensive Flutter cache manager package to cache images, videos, and other files.
Flutter App Cache Manager #
A comprehensive and flexible cache manager for Flutter applications built on top of flutter_cache_manager
. This package provides a clean architecture approach to caching with support for multiple file types, cache policies, monitoring, and maintenance operations.
π Latest Updates (v1.0.1) #
- Enhanced Type Safety: Improved safe type parsing with better error handling
- Better Architecture: Refined interface naming and code organization
- Improved Performance: Optimized cache operations and memory usage
- Enhanced Documentation: Better API documentation and examples
π Features #
Core Functionality #
- Multi-file type support: Images, videos, audio, documents, archives, and general files
- Clean Architecture: Interface-based design with dependency inversion
- Type Safety: Uses
flutter_shared_utilities
for safe type parsing with enhanced error handling - Cache Policies: TTL, LRU, FIFO, and custom expiration policies
- Priority System: Critical, high, normal, and low priority levels
Advanced Capabilities #
- Progress Monitoring: Real-time download progress tracking
- Event Streaming: Comprehensive cache event notifications
- Batch Operations: Store, retrieve, and delete multiple entries
- Cache Statistics: Hit rates, usage analytics, and performance metrics
- Integrity Validation: Checksum-based corruption detection and repair
- Smart Cleanup: Automatic maintenance with configurable policies
Configuration Options #
- File Type Specific: Optimized settings for different content types
- Network Management: WiFi-only mode, retry policies, timeouts
- Storage Control: Size limits, entry limits, compression, encryption
- Flexible TTL: Per-entry or global time-to-live settings
π¦ Installation #
Add this package to your pubspec.yaml
:
dependencies:
flutter_app_cache_manager: ^1.0.1
flutter_shared_utilities: ^1.0.7
Then run:
flutter pub get
π Quick Start #
Basic Usage #
import 'package:flutter_app_cache_manager/flutter_app_cache_manager.dart';
// Create configuration for images
final config = CacheConfigurationModel.imageConfig().copyWith(
name: 'my_app_cache',
maxCacheSize: 100 * 1024 * 1024, // 100MB
);
// Create and initialize the cache manager
final cacheManager = await FlutterCacheManagerImpl.create(config);
// Store an image
final imageEntry = await cacheManager.storeImage(
key: 'profile_image_123',
url: 'https://example.com/profile.jpg',
ttl: const Duration(days: 7),
);
// Retrieve from cache
final cachedEntry = await cacheManager.retrieve('profile_image_123');
if (cachedEntry != null) {
final file = await cacheManager.getFile('profile_image_123');
// Use the cached file
}
// Cleanup when done
await cacheManager.dispose();
Configuration Types #
The package provides pre-configured setups for different file types:
// Image-optimized configuration
final imageConfig = CacheConfigurationModel.imageConfig();
// Video-optimized configuration (WiFi-only by default)
final videoConfig = CacheConfigurationModel.videoConfig();
// Audio-optimized configuration
final audioConfig = CacheConfigurationModel.audioConfig();
// Document-optimized configuration
final documentConfig = CacheConfigurationModel.documentConfig();
// Custom configuration
final customConfig = CacheConfigurationModel(
name: 'custom_cache',
maxCacheSize: 200 * 1024 * 1024, // 200MB
maxCacheEntries: 1000,
defaultTtl: const Duration(hours: 24),
expirationPolicy: CacheExpirationPolicy.lru,
autoCleanupEnabled: true,
wifiOnlyMode: false,
);
π Detailed Usage #
Storing Different File Types #
// Store an image with specific options
final imageEntry = await cacheManager.storeImage(
key: 'user_avatar_456',
url: 'https://api.example.com/avatars/456.jpg',
ttl: const Duration(days: 30),
headers: {'Authorization': 'Bearer token'},
);
// Store a video
final videoEntry = await cacheManager.storeVideo(
key: 'tutorial_video',
url: 'https://videos.example.com/tutorial.mp4',
ttl: const Duration(days: 7),
);
// Store an audio file
final audioEntry = await cacheManager.storeAudio(
key: 'notification_sound',
url: 'https://sounds.example.com/notification.wav',
ttl: const Duration(days: 365), // Cache for a year
);
// Store a document
final docEntry = await cacheManager.storeDocument(
key: 'user_manual',
url: 'https://docs.example.com/manual.pdf',
ttl: const Duration(days: 90),
);
// Store raw data directly
final Uint8List imageData = ...; // Your image data
final dataEntry = await cacheManager.store(
key: 'generated_image',
url: 'internal://generated',
data: imageData,
fileType: CacheFileType.image,
priority: CachePriority.high,
);
Batch Operations #
// Store multiple files at once
final List<Map<String, Object?>> filesToCache = [
{
'key': 'image1',
'url': 'https://example.com/image1.jpg',
'fileType': CacheFileType.image,
},
{
'key': 'image2',
'url': 'https://example.com/image2.jpg',
'fileType': CacheFileType.image,
},
];
final List<CacheEntryModel> storedEntries = await cacheManager.storeMultiple(filesToCache);
// Retrieve multiple entries
final List<String> keys = ['image1', 'image2', 'image3'];
final List<CacheEntryModel?> entries = await cacheManager.retrieveMultiple(keys);
// Delete multiple entries
final List<bool> deleteResults = await cacheManager.deleteMultiple(keys);
// Preload URLs for faster access later
final List<String> urlsToPreload = [
'https://example.com/future-image1.jpg',
'https://example.com/future-image2.jpg',
];
await cacheManager.preloadUrls(urlsToPreload, fileType: CacheFileType.image);
Cache Management and Analytics #
// Get cache statistics
final Map<String, Object?> stats = await cacheManager.getCacheStatistics();
print('Cache hit rate: ${stats['hitRate']}%');
print('Total size: ${stats['totalSize']} bytes');
print('Total entries: ${stats['totalEntries']}');
// Get entries by different criteria
final List<CacheEntryModel> imageEntries = await cacheManager.getEntriesByType(CacheFileType.image);
final List<CacheEntryModel> highPriorityEntries = await cacheManager.getEntriesByPriority(CachePriority.high);
final List<CacheEntryModel> expiredEntries = await cacheManager.getExpiredEntries();
// Get usage statistics by file type
final Map<CacheFileType, int> usage = await cacheManager.getCacheUsageByType();
for (final entry in usage.entries) {
print('${entry.key.value}: ${entry.value} bytes');
}
// Get largest cached files
final List<CacheEntryModel> largestFiles = await cacheManager.getLargestEntries(limit: 10);
// Get most accessed files
final List<CacheEntryModel> mostAccessed = await cacheManager.getMostAccessedEntries(limit: 10);
Progress Monitoring and Events #
// Listen to cache events
final StreamSubscription eventSub = cacheManager.cacheEventStream.listen((CacheEvent event) {
switch (event.type) {
case CacheEventType.downloadStarted:
print('Download started: ${event.key}');
break;
case CacheEventType.downloadCompleted:
print('Download completed: ${event.key}');
break;
case CacheEventType.downloadFailed:
print('Download failed: ${event.key}');
break;
case CacheEventType.entryAccessed:
print('Entry accessed: ${event.key}');
break;
case CacheEventType.cleanupPerformed:
print('Cleanup performed: ${event.data}');
break;
}
});
// Listen to download progress
final StreamSubscription progressSub = cacheManager.downloadProgressStream.listen((Map<String, double> progress) {
progress.forEach((String key, double progress) {
print('$key: ${(progress * 100).toStringAsFixed(1)}% complete');
});
});
// Don't forget to cancel subscriptions
await eventSub.cancel();
await progressSub.cancel();
Cache Maintenance #
// Clean up expired entries
final int expiredCount = await cacheManager.cleanupExpired();
print('Cleaned up $expiredCount expired entries');
// Clean up by size (when cache is too large)
final int sizeCleanupCount = await cacheManager.cleanupBySize();
print('Cleaned up $sizeCleanupCount entries to reduce size');
// LRU cleanup (keep only most recently used)
final int lruCount = await cacheManager.cleanupLRU(targetCount: 100);
print('LRU cleanup removed $lruCount entries');
// Validate cache integrity
final List<String> corruptedKeys = await cacheManager.validateIntegrity();
if (corruptedKeys.isNotEmpty) {
print('Found ${corruptedKeys.length} corrupted files');
// Repair corrupted entries
final int repairedCount = await cacheManager.repairCorrupted();
print('Repaired $repairedCount corrupted entries');
}
// Comprehensive maintenance
final Map<String, int> maintenanceResults = await cacheManager.performMaintenance();
print('Maintenance results: $maintenanceResults');
// Full optimization
await cacheManager.optimize();
ποΈ Architecture #
This package follows Clean Architecture principles:
lib/
βββ src/
β βββ core/
β β βββ constants/ # Cache configuration constants
β β βββ enums/ # Cache-related enumerations
β β βββ exceptions/ # Custom exception classes
β βββ interfaces/ # Abstract cache manager interface
β βββ models/ # Data models (Entry, Configuration)
β βββ implementations/ # Concrete cache manager implementation
Key Components #
BaseCacheManagerInterface
: Base abstract interface defining common cache operationsFlutterCacheManagerImpl
: Concrete implementation using flutter_cache_managerCacheEntryModel
: Represents a cached file with metadataCacheConfigurationModel
: Cache settings and policies- Enums: Type-safe enumerations for cache policies, file types, priorities
- Exceptions: Specific exceptions for different error scenarios
π οΈ Customization #
Creating Custom Cache Managers #
class CustomCacheManager extends FlutterCacheManagerImpl {
// Add domain-specific methods
Future<CacheEntryModel> storeUserProfileImage({
required String userId,
required String imageUrl,
Uint8List? imageData,
}) async {
final key = 'user_profile_$userId';
return await storeImage(
key: key,
url: imageUrl,
imageData: imageData,
ttl: const Duration(days: 7),
priority: CachePriority.high, // Profile images are important
);
}
Future<List<CacheEntryModel>> getAllUserProfileImages() async {
final allEntries = await getAllEntries();
return allEntries.where((entry) =>
entry.key.startsWith('user_profile_') &&
entry.fileType == CacheFileType.image
).toList();
}
}
Custom Configuration #
// Create highly customized configuration
final advancedConfig = CacheConfigurationModel(
name: 'advanced_cache',
maxCacheSize: 500 * 1024 * 1024, // 500MB
maxCacheEntries: 5000,
defaultTtl: const Duration(hours: 12),
expirationPolicy: CacheExpirationPolicy.lru,
storageLevel: CacheStorageLevel.multiLevel,
autoCleanupEnabled: true,
cleanupThreshold: 0.85, // Start cleanup at 85% full
cleanupTargetRatio: 0.70, // Clean down to 70%
wifiOnlyMode: false,
maxConcurrentDownloads: 4,
networkTimeout: const Duration(seconds: 30),
downloadTimeout: const Duration(minutes: 5),
retryAttempts: 3,
retryDelay: const Duration(seconds: 2),
validateIntegrity: true,
enableCompression: true,
customHeaders: {
'User-Agent': 'MyApp/1.0',
'Cache-Control': 'max-age=3600',
},
metadata: {
'app_version': '1.0.0',
'cache_version': '2',
},
);
π§ͺ Testing #
The package is designed for testability with its interface-based architecture:
// Create a mock implementation for testing
class MockCacheManager implements BaseCacheManagerInterface {
final Map<String, CacheEntryModel> _mockCache = {};
@override
Future<CacheEntryModel> store({required String key, required String url, ...}) async {
final entry = CacheEntryModel(key: key, url: url, ...);
_mockCache[key] = entry;
return entry;
}
@override
Future<CacheEntryModel?> retrieve(String key) async {
return _mockCache[key];
}
// Implement other methods...
}
// Use in tests
void main() {
group('Cache Manager Tests', () {
late BaseCacheManagerInterface cacheManager;
setUp(() {
cacheManager = MockCacheManager();
});
test('should store and retrieve entry', () async {
// Test implementation
});
});
}
π± Integration with Flutter Widgets #
Cached Network Image Integration #
import 'package:cached_network_image/cached_network_image.dart';
class CachedImageWidget extends StatelessWidget {
final String imageUrl;
final FlutterCacheManagerImpl cacheManager;
const CachedImageWidget({
super.key,
required this.imageUrl,
required this.cacheManager,
});
@override
Widget build(BuildContext context) {
return CachedNetworkImage(
imageUrl: imageUrl,
cacheManager: cacheManager._cacheManagers[CacheFileType.image],
placeholder: (context, url) => const CircularProgressIndicator(),
errorWidget: (context, url, error) => const Icon(Icons.error),
fadeInDuration: const Duration(milliseconds: 300),
);
}
}
Progress Indicator #
class DownloadProgressWidget extends StatefulWidget {
final String cacheKey;
final FlutterCacheManagerImpl cacheManager;
const DownloadProgressWidget({
super.key,
required this.cacheKey,
required this.cacheManager,
});
@override
State<DownloadProgressWidget> createState() => _DownloadProgressWidgetState();
}
class _DownloadProgressWidgetState extends State<DownloadProgressWidget> {
double _progress = 0.0;
late StreamSubscription _subscription;
@override
void initState() {
super.initState();
_subscription = widget.cacheManager.downloadProgressStream.listen((progress) {
if (progress.containsKey(widget.cacheKey)) {
setState(() {
_progress = progress[widget.cacheKey]!;
});
}
});
}
@override
Widget build(BuildContext context) {
return LinearProgressIndicator(value: _progress);
}
@override
void dispose() {
_subscription.cancel();
super.dispose();
}
}
β‘ Performance Tips #
- Use appropriate TTL values: Don't cache files longer than necessary
- Set reasonable cache sizes: Monitor storage usage and adjust limits
- Enable cleanup: Let the cache manager handle maintenance automatically
- Use priorities: Mark critical files as high priority to prevent cleanup
- Batch operations: Use
storeMultiple
/retrieveMultiple
for better performance - Monitor hit rates: Low hit rates might indicate inefficient caching strategies
π Security Considerations #
- Enable encryption for sensitive cached data
- Validate checksums to ensure data integrity
- Use HTTPS URLs for all network requests
- Clear cache when users log out
- Set appropriate TTL for sensitive content
π Troubleshooting #
Common Issues #
Cache not initializing
// Use the factory constructor to create and initialize
final cacheManager = await FlutterCacheManagerImpl.create(configuration);
Files not being cached
// Check if cache is enabled
print('Cache enabled: ${cacheManager.isEnabled}');
// Verify configuration
print('Max cache size: ${cacheManager.configuration.maxCacheSize}');
High memory usage
// Enable cleanup and set reasonable limits
final config = CacheConfigurationModel.imageConfig().copyWith(
maxCacheSize: 50 * 1024 * 1024, // 50MB
autoCleanupEnabled: true,
cleanupThreshold: 0.8,
);
Debug Mode #
Enable debug mode for detailed logging:
final debugConfig = configuration.copyWith(debugMode: true);
final cacheManager = await FlutterCacheManagerImpl.create(debugConfig);
π€ Contributing #
Contributions are welcome! Please read our contributing guidelines and submit pull requests for any improvements.
π License #
This project is licensed under the MIT License - see the LICENSE file for details.
π Acknowledgments #
- Built on top of flutter_cache_manager
- Uses flutter_shared_utilities for safe type parsing
- Inspired by clean architecture principles
π API Reference #
Core Classes #
BaseCacheManagerInterface
Abstract interface defining all cache operations.
FlutterCacheManagerImpl
Main implementation class providing comprehensive caching functionality.
CacheEntryModel
Represents a cached file with comprehensive metadata including:
- File information (size, type, path)
- Cache metadata (TTL, priority, tags)
- Access statistics (hit count, last accessed)
- Integrity data (checksum, corruption status)
CacheConfigurationModel
Configuration class with factory methods for different file types:
defaultConfig()
- Basic configurationimageConfig()
- Optimized for imagesvideoConfig()
- Optimized for videos (WiFi-only by default)audioConfig()
- Optimized for audio filesdocumentConfig()
- Optimized for documents
Enums #
CacheFileType
: image, video, audio, document, archive, generalCacheExpirationPolicy
: never, ttl, lastAccessed, lru, fifo, customCachePriority
: low, normal, high, criticalCacheStorageLevel
: memory, disk, multiLevel
For complete API documentation, see the inline documentation in the source code.