flutter_async_cache

A smart caching system for Flutter applications with automatic refresh, offline support, and cache invalidation.

Features

  • πŸš€ Smart Caching: Intelligent cache management with multiple eviction strategies
  • πŸ”„ Automatic Refresh: Background refresh of expired cache entries
  • πŸ“± Offline Support: Serve cached data when network is unavailable
  • πŸ—‘οΈ Cache Invalidation: Pattern-based cache invalidation
  • πŸ“Š Statistics: Detailed cache performance metrics
  • πŸ’Ύ Persistence: Automatic cache persistence across app restarts
  • ⚑ High Performance: Optimized for speed and memory usage
  • 🎯 Flexible Configuration: Multiple pre-configured strategies for different use cases

Installation

Add this to your package's pubspec.yaml file:

dependencies:
  flutter_async_cache: ^0.0.3

Quick Start

import 'package:flutter_async_cache/flutter_async_cache.dart';

void main() async {
  // Create a cache manager
  final cache = CacheManager();
  
  // Initialize the cache
  await cache.initialize();
  
  // Use the cache to fetch and store data
  final userData = await cache.get(
    'user_profile',
    () async {
      // This function will be called if data is not in cache
      return await fetchUserProfileFromAPI();
    },
    ttl: Duration(hours: 1), // Cache for 1 hour
  );
  
  // Listen to cache events
  cache.onCacheEvent.listen((event) {
    print('Cache event: $event');
  });
  
  // Get cache statistics
  print('Cache stats: ${cache.statistics}');
}

Configuration

Pre-configured Strategies

// Default configuration
final cache = CacheManager();

// Memory-optimized configuration
final memoryCache = CacheManager(
  config: CacheConfig.memoryOptimized,
);

// Performance-optimized configuration
final performanceCache = CacheManager(
  config: CacheConfig.performanceOptimized,
);

// Offline-first configuration
final offlineCache = CacheManager(
  config: CacheConfig.offlineFirst,
);

Custom Configuration

final customCache = CacheManager(
  config: CacheConfig(
    maxEntries: 500,
    maxSize: 50 * 1024 * 1024, // 50MB
    defaultTtl: Duration(hours: 2),
    enableOfflineMode: true,
    enableBackgroundRefresh: true,
    backgroundRefreshInterval: Duration(minutes: 10),
    enableAutoCleanup: true,
    autoCleanupInterval: Duration(hours: 2),
    evictionStrategy: EvictionStrategy.lru,
    enableStatistics: true,
    enablePersistence: true,
  ),
);

Usage Examples

Basic API Caching

class UserService {
  final CacheManager _cache = CacheManager();
  
  Future<void> initialize() async {
    await _cache.initialize();
  }
  
  Future<User> getUser(int userId) async {
    return await _cache.get(
      'user_$userId',
      () async {
        final response = await http.get('/api/users/$userId');
        return User.fromJson(jsonDecode(response.body));
      },
      ttl: Duration(minutes: 30),
    );
  }
  
  Future<void> refreshUser(int userId) async {
    return await _cache.get(
      'user_$userId',
      () async {
        final response = await http.get('/api/users/$userId');
        return User.fromJson(jsonDecode(response.body));
      },
      forceRefresh: true, // Force refresh from API
    );
  }
}

Offline-First Data Loading

class NewsService {
  final CacheManager _cache = CacheManager(
    config: CacheConfig.offlineFirst,
  );
  
  Future<List<Article>> getNews() async {
    return await _cache.get(
      'news_articles',
      () async {
        final response = await http.get('/api/news');
        return (jsonDecode(response.body) as List)
            .map((json) => Article.fromJson(json))
            .toList();
      },
      ttl: Duration(hours: 6),
    );
  }
}

Cache Invalidation

class ProductService {
  final CacheManager _cache = CacheManager();
  
  Future<void> updateProduct(Product product) async {
    // Update product in API
    await http.put('/api/products/${product.id}', body: product.toJson());
    
    // Invalidate all product-related cache entries
    await _cache.invalidatePattern('product_.*');
    
    // Or invalidate specific product
    await _cache.remove('product_${product.id}');
  }
}

Cache Statistics

class CacheMonitor {
  final CacheManager _cache = CacheManager();
  
  void monitorCache() {
    // Listen to cache events
    _cache.onCacheEvent.listen((event) {
      switch (event.runtimeType) {
        case _HitEvent:
          print('Cache hit: ${(event as _HitEvent).key}');
          break;
        case _MissEvent:
          print('Cache miss: ${(event as _MissEvent).key}');
          break;
        case _OfflineHitEvent:
          print('Offline cache hit: ${(event as _OfflineHitEvent).key}');
          break;
      }
    });
    
    // Get statistics
    Timer.periodic(Duration(minutes: 5), (timer) {
      final stats = _cache.statistics;
      print('Cache Statistics:');
      print('  Hit Rate: ${(stats.hitRate * 100).toStringAsFixed(1)}%');
      print('  Total Hits: ${stats.hits}');
      print('  Total Misses: ${stats.misses}');
      print('  Evictions: ${stats.evictions}');
      print('  Entries: ${stats.entryCount}');
      print('  Size: ${(stats.totalSize / 1024).toStringAsFixed(1)}KB');
    });
  }
}

Eviction Strategies

The package supports multiple cache eviction strategies:

  • LRU (Least Recently Used): Evicts the least recently accessed entry
  • LFU (Least Frequently Used): Evicts the least frequently accessed entry
  • FIFO (First In First Out): Evicts the oldest entry
  • Random: Evicts a random entry
  • Time-based: Evicts expired entries first, then oldest

API Reference

CacheManager

Methods

  • initialize(): Initialize the cache manager
  • get<T>(key, fetcher, {ttl, forceRefresh, metadata}): Get or fetch data
  • set<T>(key, data, {ttl, metadata}): Set data in cache
  • remove(key): Remove an entry from cache
  • clear(): Clear all cache entries
  • contains(key): Check if key exists in cache
  • invalidatePattern(pattern): Invalidate entries matching pattern
  • dispose(): Dispose of the cache manager

Properties

  • keys: List of all cache keys
  • size: Total cache size in bytes
  • length: Number of cache entries
  • statistics: Cache performance statistics
  • onCacheEvent: Stream of cache events

CacheConfig

Properties

  • maxEntries: Maximum number of entries
  • maxSize: Maximum cache size in bytes
  • defaultTtl: Default time-to-live for entries
  • enableOfflineMode: Enable offline support
  • enableBackgroundRefresh: Enable background refresh
  • backgroundRefreshInterval: Background refresh interval
  • enableAutoCleanup: Enable automatic cleanup
  • autoCleanupInterval: Automatic cleanup interval
  • evictionStrategy: Cache eviction strategy
  • enableStatistics: Enable cache statistics
  • enablePersistence: Enable cache persistence

Contributing

  1. Fork the repository
  2. Create your feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add some amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

License

This project is licensed under the MIT License - see the LICENSE file for details.

Changelog

0.0.1

  • Initial release
  • Basic caching functionality
  • Multiple eviction strategies
  • Offline support
  • Cache persistence
  • Statistics and monitoring
  • Event system