flutter_async_cache 0.0.3
flutter_async_cache: ^0.0.3 copied to clipboard
A smart caching system for API calls with automatic refresh, offline support, and cache invalidation
import 'package:flutter/material.dart';
import 'package:flutter_async_cache/flutter_async_cache.dart';
import 'dart:convert';
import 'package:http/http.dart' as http;
void main() {
runApp(const CacheExampleApp());
}
class CacheExampleApp extends StatelessWidget {
const CacheExampleApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Async Cache Example',
theme: ThemeData(
primarySwatch: Colors.blue,
useMaterial3: true,
),
home: const CacheExamplePage(),
);
}
}
class CacheExamplePage extends StatefulWidget {
const CacheExamplePage({super.key});
@override
State<CacheExamplePage> createState() => _CacheExamplePageState();
}
class _CacheExamplePageState extends State<CacheExamplePage> {
late CacheManager cache;
String currentData = 'No data loaded';
String cacheStats = '';
List<String> events = [];
@override
void initState() {
super.initState();
_initializeCache();
}
Future<void> _initializeCache() async {
cache = CacheManager(
config: CacheConfig(
maxEntries: 50,
maxSize: 10 * 1024 * 1024, // 10MB
defaultTtl: Duration(minutes: 5),
enableOfflineMode: true,
enableBackgroundRefresh: true,
backgroundRefreshInterval: Duration(minutes: 2),
enableAutoCleanup: true,
autoCleanupInterval: Duration(minutes: 10),
evictionStrategy: EvictionStrategy.lru,
enableStatistics: true,
enablePersistence: true,
),
);
await cache.initialize();
// Listen to cache events
cache.onCacheEvent.listen((event) {
setState(() {
events.add(
'${DateTime.now().toString().substring(11, 19)}: ${event.runtimeType}');
if (events.length > 10) {
events.removeAt(0);
}
});
});
_updateStats();
}
void _updateStats() {
final stats = cache.statistics;
setState(() {
cacheStats = '''
Cache Statistics:
Hit Rate: ${(stats.hitRate * 100).toStringAsFixed(1)}%
Hits: ${stats.hits}
Misses: ${stats.misses}
Evictions: ${stats.evictions}
Entries: ${stats.entryCount}
Size: ${(stats.totalSize / 1024).toStringAsFixed(1)}KB
''';
});
}
Future<Map<String, dynamic>> _fetchUserData(int userId) async {
// Simulate API call
await Future.delayed(Duration(milliseconds: 500));
// Simulate network request
final response = await http.get(
Uri.parse('https://jsonplaceholder.typicode.com/users/$userId'),
);
if (response.statusCode == 200) {
return jsonDecode(response.body) as Map<String, dynamic>;
} else {
throw Exception('Failed to load user data');
}
}
Future<void> _loadUserData(int userId) async {
try {
final userData = await cache.get(
'user_$userId',
() => _fetchUserData(userId),
ttl: Duration(minutes: 10),
);
setState(() {
currentData = jsonEncode(userData);
});
_updateStats();
} catch (e) {
setState(() {
currentData = 'Error: $e';
});
}
}
Future<void> _forceRefreshUserData(int userId) async {
try {
final userData = await cache.get(
'user_$userId',
() => _fetchUserData(userId),
forceRefresh: true,
);
setState(() {
currentData = 'Refreshed: ${jsonEncode(userData)}';
});
_updateStats();
} catch (e) {
setState(() {
currentData = 'Error: $e';
});
}
}
Future<void> _clearCache() async {
await cache.clear();
setState(() {
currentData = 'Cache cleared';
});
_updateStats();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Flutter Async Cache Example'),
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
),
body: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Card(
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
'Cache Actions',
style:
TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
),
const SizedBox(height: 16),
Row(
children: [
Expanded(
child: ElevatedButton(
onPressed: () => _loadUserData(1),
child: const Text('Load User 1'),
),
),
const SizedBox(width: 8),
Expanded(
child: ElevatedButton(
onPressed: () => _loadUserData(2),
child: const Text('Load User 2'),
),
),
],
),
const SizedBox(height: 8),
Row(
children: [
Expanded(
child: ElevatedButton(
onPressed: () => _forceRefreshUserData(1),
child: const Text('Force Refresh'),
),
),
const SizedBox(width: 8),
Expanded(
child: ElevatedButton(
onPressed: _clearCache,
child: const Text('Clear Cache'),
),
),
],
),
],
),
),
),
const SizedBox(height: 16),
Card(
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
'Current Data',
style:
TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
),
const SizedBox(height: 8),
Container(
padding: const EdgeInsets.all(8),
decoration: BoxDecoration(
color: Colors.grey[100],
borderRadius: BorderRadius.circular(4),
),
child: Text(
currentData,
style: const TextStyle(fontFamily: 'monospace'),
),
),
],
),
),
),
const SizedBox(height: 16),
Card(
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
'Cache Statistics',
style:
TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
),
const SizedBox(height: 8),
Text(
cacheStats,
style: const TextStyle(fontFamily: 'monospace'),
),
],
),
),
),
const SizedBox(height: 16),
Card(
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
'Recent Events',
style:
TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
),
const SizedBox(height: 8),
Container(
height: 120,
decoration: BoxDecoration(
color: Colors.grey[100],
borderRadius: BorderRadius.circular(4),
),
child: ListView.builder(
itemCount: events.length,
itemBuilder: (context, index) {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 2),
child: Text(
events[events.length - 1 - index],
style: const TextStyle(fontSize: 12),
),
);
},
),
),
],
),
),
),
],
),
),
);
}
@override
void dispose() {
cache.dispose();
super.dispose();
}
}