data_cache_x 1.0.0 copy "data_cache_x: ^1.0.0" to clipboard
data_cache_x: ^1.0.0 copied to clipboard

A Flutter package for efficient offline data caching and synchronization with enhanced security features and tag-based cache management.

data_cache_x logo

DataCacheX

A versatile and extensible caching library for Dart and Flutter applications

Pub License: MIT


๐Ÿ“‹ Overview #

DataCacheX is a powerful caching solution designed to simplify data management in your Dart and Flutter applications. It provides a flexible and efficient way to store and retrieve data with support for multiple storage backends, advanced caching policies, and comprehensive analytics.

Why Choose DataCacheX? #

  • Multiple Storage Options: Choose from memory, Hive, SQLite, or SharedPreferences adapters
  • Flexible Caching Policies: Configure expiry, compression, encryption, and priority
  • Enhanced Security: Multiple encryption algorithms (AES-256, ChaCha20, Salsa20) and secure key storage
  • Tag-Based Management: Organize and selectively invalidate cache items using tags
  • Memory Management: Automatic cleanup and multiple eviction strategies
  • Performance Analytics: Track cache performance with built-in metrics
  • Type Safety: Full support for generic types and complex data structures
  • Extensibility: Easy to extend with custom adapters and serializers
  • Batch Operations: Efficiently process multiple items at once for improved performance
  • Cache Synchronization: Keep multiple cache instances in sync with advanced sync controls
  • Advanced Eviction Scheduling: Fine-grained control over when and how cache cleanup happens, including time-based scheduling
  • Cache Preloading: Proactively load data into the cache before it's needed

๐Ÿš€ Installation #

Add data_cache_x to your pubspec.yaml file:

dependencies:
  data_cache_x: ^latest_version

Then run:

flutter pub get

๐Ÿ”ง Quick Start #

Initialize the Package #

import 'package:data_cache_x/data_cache_x.dart';
import 'package:data_cache_x/service_locator.dart';

Future<void> main() async {
  // Initialize with default settings (Hive adapter)
  await setupDataCacheX();

  // Get the DataCacheX instance
  final dataCache = getIt<DataCacheX>();

  // Start using the cache
  await dataCache.put('greeting', 'Hello, World!');
  final value = await dataCache.get<String>('greeting');
  print(value); // Output: Hello, World!
}

Choose a Different Adapter #

// Use memory adapter (volatile, but fast)
await setupDataCacheX(adapterType: CacheAdapterType.memory);

// Use SQLite adapter (persistent, good for larger datasets)
await setupDataCacheX(adapterType: CacheAdapterType.sqlite);

// Use SharedPreferences adapter (persistent, simple key-value storage)
await setupDataCacheX(adapterType: CacheAdapterType.sharedPreferences);

๐Ÿ“š Core Features #

Basic Cache Operations #

// Store values with optional expiry
await dataCache.put('user_profile', userProfile,
    expiry: Duration(hours: 24));

// Retrieve values with type safety
final profile = await dataCache.get<UserProfile>('user_profile');

// Check if a key exists
final exists = await dataCache.containsKey('user_profile');

// Delete a value
await dataCache.delete('user_profile');

// Clear the entire cache
await dataCache.clear();

Batch Operations #

// Store multiple values at once
await dataCache.putAll({
  'user': currentUser,
  'settings': appSettings,
  'theme': currentTheme,
}, policy: CachePolicy(expiry: Duration(days: 7)));

// Retrieve multiple values
final values = await dataCache.getAll<dynamic>([
  'user', 'settings', 'theme'
]);

// Delete multiple values
await dataCache.deleteAll(['user', 'settings', 'theme']);

// Track batch operation performance
final batchStats = await dataCache.getBatchStats();
print('Average batch write time: ${batchStats.avgWriteTime}ms');
print('Average batch read time: ${batchStats.avgReadTime}ms');
print('Batch operation count: ${batchStats.operationCount}');

// Compare batch vs individual operations
final benchmark = AdapterBenchmark(
  itemCount: 1000,
  itemSize: 500,
  benchmarkType: BenchmarkType.batch,
);
final result = await benchmarkService.runBenchmark('hive', benchmark);
print('Batch write time: ${result.writeTime}ms');
print('Standard write time: ${result.standardWriteTime}ms');
print('Performance improvement: ${result.performanceImprovement}%');

Advanced Caching Policies #

// Create a custom policy
final myPolicy = CachePolicy(
  expiry: Duration(hours: 24),         // Fixed expiry time
  slidingExpiry: Duration(hours: 2),    // Extends on each access
  staleTime: Duration(minutes: 30),     // Time before refresh
  priority: CachePriority.high,         // Higher priority in eviction
  refreshStrategy: RefreshStrategy.backgroundRefresh,
  maxSize: 1024 * 10,                   // 10 KB max size
  encrypt: true,                        // Enable encryption
  encryptionAlgorithm: EncryptionAlgorithm.aes256, // Encryption algorithm
  compression: CompressionMode.auto,    // Auto-compress if beneficial
);

// Apply the policy
await dataCache.put('important_data', data, policy: myPolicy);

// Use predefined policies
await dataCache.put('sensitive_data', userData,
    policy: CachePolicy.encrypted(expiry: Duration(days: 7)));

await dataCache.put('temp_data', tempData,
    policy: CachePolicy.temporary);

await dataCache.put('large_data', largeData,
    policy: CachePolicy.compressed());

Auto-Refresh with Callbacks #

// Get data with auto-refresh when stale
final userData = await dataCache.get<UserData>('user_data',
  refreshCallback: () => fetchUserFromApi(),  // Called when data is stale/expired
  policy: CachePolicy(
    staleTime: Duration(minutes: 5),
    refreshStrategy: RefreshStrategy.backgroundRefresh,
  ),
);

// Multiple items with different refresh callbacks
final data = await dataCache.getAll<dynamic>(['users', 'posts', 'comments'],
  refreshCallbacks: {
    'users': () => fetchUsersFromApi(),
    'posts': () => fetchPostsFromApi(),
    'comments': () => fetchCommentsFromApi(),
  },
  policy: CachePolicy(staleTime: Duration(minutes: 10)),
);

Enhanced Encryption #

// Initialize with encryption options
import 'package:data_cache_x/utils/encryption.dart';
import 'package:data_cache_x/models/encryption_options.dart';

// Create encryption options with AES-256
final aesOptions = EncryptionOptions.aes256(
  key: 'your-secure-encryption-key-here',
);

// Generate a random secure key
final randomKeyOptions = EncryptionOptions.withRandomKey(
  algorithm: EncryptionAlgorithm.aes256,
);

// Derive a key from a password
final passwordOptions = EncryptionOptions.fromPassword(
  password: 'user-password',
  salt: 'random-salt-value',
  algorithm: EncryptionAlgorithm.aes256,
);

// Initialize cache with encryption
await setupDataCacheX(
  enableEncryption: true,
  encryptionOptions: aesOptions,
);

Tag-Based Cache Management #

// Store items with tags
await dataCache.put('user_1', userData1, tags: {'users', 'active'});
await dataCache.put('user_2', userData2, tags: {'users', 'inactive'});
await dataCache.put('product_1', product1, tags: {'products', 'featured'});

// Store multiple items with the same tags
await dataCache.putAll({
  'order_1': order1,
  'order_2': order2,
  'order_3': order3,
}, tags: {'orders', 'recent'});

// Get all keys with a specific tag
final userKeys = await dataCache.getKeysByTag('users');

// Get all keys with multiple tags
final activeUserKeys = await dataCache.getKeysByTags(['users', 'active']);

// Get all items with a specific tag
final allUsers = await dataCache.getByTag<UserData>('users');

// Delete all items with a specific tag
await dataCache.deleteByTag('inactive');

// Delete all items with multiple tags
await dataCache.deleteByTags(['orders', 'recent']);

๐Ÿ” Advanced Features #

Memory Management with Eviction Strategies #

// Create a cache with LRU (Least Recently Used) eviction
final lruCache = DataCacheX(
  cacheAdapter,
  maxSize: 10 * 1024 * 1024,  // 10 MB max size
  maxItems: 1000,             // 1000 items max
  evictionStrategy: EvictionStrategy.lru,
);

// Other available strategies
// LFU (Least Frequently Used)
final lfuCache = DataCacheX(
  cacheAdapter,
  evictionStrategy: EvictionStrategy.lfu,
);

// FIFO (First In, First Out)
final fifoCache = DataCacheX(
  cacheAdapter,
  evictionStrategy: EvictionStrategy.fifo,
);

// TTL (Time To Live - prioritizes items closest to expiration)
final ttlCache = DataCacheX(
  cacheAdapter,
  evictionStrategy: EvictionStrategy.ttl,
);

Advanced Eviction Scheduling #

import 'package:data_cache_x/data_cache_x.dart';
import 'package:get_it/get_it.dart';

// Get the settings repository
final settingsRepo = GetIt.instance<SettingsRepository>();

// Configure periodic eviction (runs at regular intervals)
final periodicSettings = CacheSettings(
  evictionScheduleType: ScheduleType.periodic,
  cleanupFrequency: Duration(minutes: 30),
  evictionStrategy: EvictionStrategy.lru,
);
await settingsRepo.saveSettings(periodicSettings);

// Configure scheduled eviction (runs at specific times)
final scheduledSettings = CacheSettings(
  evictionScheduleType: ScheduleType.scheduled,
  scheduledTimes: ['03:00', '15:00'], // Run at 3 AM and 3 PM
  evictionStrategy: EvictionStrategy.lru,
);
await settingsRepo.saveSettings(scheduledSettings);

// Configure idle-based eviction (runs when app is idle)
final idleSettings = CacheSettings(
  evictionScheduleType: ScheduleType.onIdle,
  evictionStrategy: EvictionStrategy.lfu,
);
await settingsRepo.saveSettings(idleSettings);

// Configure background eviction (runs when app is in background)
final backgroundSettings = CacheSettings(
  evictionScheduleType: ScheduleType.inBackground,
  evictionStrategy: EvictionStrategy.ttl,
);
await settingsRepo.saveSettings(backgroundSettings);

// Add a new scheduled time
final currentSettings = await settingsRepo.getSettings();
final updatedTimes = List<String>.from(currentSettings.scheduledTimes)..add('21:00');
final updatedSettings = currentSettings.copyWith(scheduledTimes: updatedTimes);
await settingsRepo.saveSettings(updatedSettings);

// Run eviction immediately
await settingsRepo.runEvictionNow();

Data Compression #

// Create a cache with compression support
final compressedCache = DataCacheX(
  cacheAdapter,
  compressionLevel: 6,  // 1 (fastest) to 9 (most compression)
);

// Auto compression (only compresses if beneficial)
await dataCache.put('large_text', largeString,
    policy: CachePolicy(compression: CompressionMode.auto));

// Always compress
await dataCache.put('always_compressed', value,
    policy: CachePolicy(compression: CompressionMode.always));

// Never compress
await dataCache.put('never_compressed', value,
    policy: CachePolicy(compression: CompressionMode.never));

Cache Analytics #

// Get basic metrics
print('Hit rate: ${dataCache.hitRate}%');
print('Total size: ${dataCache.totalSize} bytes');
print('Average item size: ${dataCache.averageItemSize} bytes');

// Get most frequently accessed keys
final topKeys = dataCache.mostFrequentlyAccessedKeys;
for (final entry in topKeys) {
  print('${entry.key}: ${entry.value} accesses');
}

// Get largest items
final largestItems = dataCache.largestItems;
for (final entry in largestItems) {
  print('${entry.key}: ${entry.value} bytes');
}

// Get complete analytics summary
final summary = dataCache.getAnalyticsSummary();
print(summary);

// Reset metrics
dataCache.resetMetrics();

Background Cleanup #

import 'package:data_cache_x/utils/background_cleanup.dart';

// Initialize background cleanup (automatically done by setupDataCacheX)
// But you can manually control it if needed:
BackgroundCleanup.initializeBackgroundCleanup(
  adapter: cacheAdapter,
  frequency: Duration(hours: 1),
);

// Stop background cleanup
BackgroundCleanup.stopBackgroundCleanup();

// Manually trigger cleanup
BackgroundCleanup.performCleanup(cacheAdapter);

Cache Synchronization #

import 'package:data_cache_x/data_cache_x.dart';
import 'package:get_it/get_it.dart';

// Get the sync repository
final syncRepo = GetIt.instance<SyncRepository>();

// Start synchronization process
await syncRepo.startSync();

// Check sync status
final bool isInSync = await syncRepo.checkSyncStatus();

// Force synchronization of specific keys
await syncRepo.syncItems(['user_profile', 'settings']);

// Listen for sync events
syncRepo.syncEvents.listen((SyncEvent event) {
  print('Sync event: ${event.type} - ${event.message}');

  if (event.type == SyncEventType.completed) {
    print('Sync completed successfully!');
  } else if (event.type == SyncEventType.error) {
    print('Sync error: ${event.error}');
  }
});

// Pause synchronization
await syncRepo.pauseSync();

// Resume synchronization
await syncRepo.resumeSync();

// Stop synchronization
await syncRepo.stopSync();

// Get sync statistics
final stats = await syncRepo.getSyncStats();
print('Total synced items: ${stats.totalSyncedItems}');
print('Last sync time: ${stats.lastSyncTime}');
print('Sync success rate: ${stats.successRate}%');

Cache Preloading #

import 'package:data_cache_x/data_cache_x.dart';

// Create a cache instance
final cache = DataCacheX(...);

// Create a preloader
final preloader = CachePreloader(cache);

// Define data providers
final dataProviders = <String, Future<dynamic> Function()>{
  'user_profile': () => fetchUserProfile(),
  'app_settings': () => fetchAppSettings(),
  'recent_items': () => fetchRecentItems(),
};

// Preload the data
final operations = await preloader.preload(dataProviders: dataProviders);

// Preload with a policy
await preloader.preload(
  dataProviders: dataProviders,
  policy: CachePolicy(
    expiry: Duration(days: 1),
    priority: CachePriority.high,
  ),
);

// Preload with tags
await preloader.preload(
  dataProviders: dataProviders,
  tags: {'preloaded', 'initial_data'},
);

// Preload in the background
final stream = preloader.preloadInBackground(
  dataProviders: dataProviders,
  onProgress: (key, status, progress) {
    print('$key: $status - ${(progress * 100).toStringAsFixed(1)}%');
  },
);

// Cancel a specific preload operation
preloader.cancelPreload('user_profile');

// Cancel all preload operations
preloader.cancelAllPreloads();

// Clear completed operations to free up memory
preloader.clearCompletedOperations();

// Dispose the preloader when done
preloader.dispose();

Custom Adapters and Serializers #

import 'package:data_cache_x/serializers/data_serializer.dart';
import 'dart:convert';

// Define a custom data type
class UserProfile {
  final String name;
  final int age;

  UserProfile({required this.name, required this.age});
}

// Create a serializer for the custom type
class UserProfileSerializer implements DataSerializer<UserProfile> {
  @override
  UserProfile fromJson(String json) {
    final map = jsonDecode(json);
    return UserProfile(name: map['name'], age: map['age']);
  }

  @override
  String toJson(UserProfile value) {
    return jsonEncode({'name': value.name, 'age': value.age});
  }
}

// Register the custom serializer
await setupDataCacheX(
  customSerializers: {
    UserProfile: UserProfileSerializer(),
  },
);

๐Ÿงช Example App #

The package includes a comprehensive example app (CacheHub) that demonstrates all features:

  • News Feed: API caching with different policies and tag-based content discovery
  • Image Gallery: Binary data caching for images with tag-based organization
  • Analytics: Cache performance visualization
  • Explorer: Browse and manipulate cached data with tag filtering
  • Adapter Playground: Benchmark different adapters and compare batch vs standard operations
  • Settings: Configure cache behavior including eviction scheduling options
  • Sync: Synchronize between multiple cache instances

To run the example app:

cd example
flutter pub get
flutter run

๐Ÿ“˜ API Reference #

DataCacheX Class #

Method Description
Future<void> put<T>(String key, T value, {CachePolicy? policy}) Stores a value in the cache
Future<T?> get<T>(String key, {Function? refreshCallback, CachePolicy? policy}) Retrieves a value from the cache
Future<void> delete(String key) Deletes a value from the cache
Future<void> clear() Clears the entire cache
Future<bool> containsKey(String key) Checks if a key exists and hasn't expired
Future<void> putAll(Map<String, dynamic> entries, {CachePolicy? policy}) Stores multiple values at once
Future<Map<String, T?>> getAll<T>(List<String> keys, {Map<String, Function>? refreshCallbacks, CachePolicy? policy}) Retrieves multiple values at once
Future<void> deleteAll(List<String> keys) Deletes multiple values at once
Future<void> invalidate(String key) Explicitly invalidates a cache entry
Future<void> invalidateWhere(bool Function(String, dynamic) test) Invalidates entries matching a condition

Cache Adapters #

  • CacheAdapterType.hive: Hive NoSQL database (persistent)
  • CacheAdapterType.memory: In-memory storage (volatile)
  • CacheAdapterType.sqlite: SQLite database (persistent)
  • CacheAdapterType.sharedPreferences: SharedPreferences (persistent)

Eviction Strategies #

  • EvictionStrategy.lru: Least Recently Used
  • EvictionStrategy.lfu: Least Frequently Used
  • EvictionStrategy.fifo: First In, First Out
  • EvictionStrategy.ttl: Time To Live (expiry-based)

Cache Priorities #

  • CachePriority.low: Evicted first
  • CachePriority.normal: Default priority
  • CachePriority.high: Higher retention priority
  • CachePriority.critical: Evicted last

Compression Modes #

  • CompressionMode.auto: Compress only if beneficial
  • CompressionMode.always: Always compress
  • CompressionMode.never: Never compress

Encryption Algorithms #

  • EncryptionAlgorithm.aes256: AES-256 encryption (default)

Tag-Based Cache API Reference #

Method Description
Future<List<String>> getKeysByTag(String tag, {int? limit, int? offset}) Gets keys with a specific tag
Future<List<String>> getKeysByTags(List<String> tags, {int? limit, int? offset}) Gets keys with all specified tags
Future<void> deleteByTag(String tag) Deletes all items with a specific tag
Future<void> deleteByTags(List<String> tags) Deletes all items with all specified tags
Future<Map<String, T>> getByTag<T>(String tag, {CachePolicy? policy}) Gets all items with a specific tag
Future<Map<String, T>> getByTags<T>(List<String> tags, {CachePolicy? policy}) Gets all items with all specified tags

Secure Key Storage #

import 'package:data_cache_x/utils/secure_storage.dart';

// Create a secure storage instance
final secureStorage = SecureStorage();

// Generate and store a random encryption key
final encryptionOptions = await secureStorage.generateAndStoreKey(
  algorithm: EncryptionAlgorithm.aes256,
);

// Derive a key from a password
final encryptionOptions = await secureStorage.deriveAndStoreKey(
  password: 'my-secure-password',
  salt: 'random-salt-value',
  algorithm: EncryptionAlgorithm.chacha20,
  iterations: 10000,
);

// Retrieve stored encryption options
final encryptionOptions = await secureStorage.getEncryptionOptions();

// Initialize cache with encryption
await setupDataCacheX(
  enableEncryption: true,
  encryptionOptions: encryptionOptions,
);

๐Ÿ“„ License #

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

1
likes
150
points
99
downloads

Publisher

unverified uploader

Weekly Downloads

A Flutter package for efficient offline data caching and synchronization with enhanced security features and tag-based cache management.

Homepage
Repository (GitHub)

Documentation

API reference

License

MIT (license)

Dependencies

archive, crypto, encrypt, flutter, flutter_secure_storage, get_it, hive, hive_flutter, logging, path, shared_preferences, sqflite

More

Packages that depend on data_cache_x