syncache_flutter 0.6.0
syncache_flutter: ^0.6.0 copied to clipboard
Flutter integration for Syncache - lifecycle management, widgets, and connectivity detection.
syncache_flutter #
Flutter integration for Syncache - lifecycle management, widgets, and connectivity detection.
Installation #
dependencies:
syncache: ^0.6.0
syncache_flutter: ^0.6.0
Quick Start #
1. Provide the cache with SyncacheScope #
Wrap your app (or a subtree) with SyncacheScope to provide cache instances to descendants:
import 'package:flutter/material.dart';
import 'package:syncache/syncache.dart';
import 'package:syncache_flutter/syncache_flutter.dart';
class User {
final String name;
const User(this.name);
}
class MyApp extends StatelessWidget {
const MyApp({required this.cache});
final Syncache<User> cache;
@override
Widget build(BuildContext context) => const SizedBox.shrink();
}
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
// Initialize connectivity detection
final network = FlutterNetwork();
await network.initialize();
// Create your cache
final userCache = Syncache<User>(
store: MemoryStore<User>(),
network: network,
);
runApp(
SyncacheScope<User>(
cache: userCache,
network: network,
child: MyApp(cache: userCache),
),
);
}
2. Display cached data with CacheBuilder #
Use CacheBuilder to reactively display cached data:
import 'package:flutter/material.dart';
import 'package:syncache/syncache.dart';
import 'package:syncache_flutter/syncache_flutter.dart';
class User {
final String name;
const User(this.name);
}
final api = Api();
class Api {
Future<User> getUser(String id) async => User('User');
}
class UserProfile extends StatelessWidget {
final String userId;
const UserProfile({required this.userId});
@override
Widget build(BuildContext context) {
return CacheBuilder<User>(
cacheKey: 'user:$userId',
fetch: (request) => api.getUser(userId),
builder: (context, snapshot) {
if (snapshot.hasError) {
return ErrorWidget(snapshot.error!);
}
if (!snapshot.hasData) {
return const CircularProgressIndicator();
}
return Text('Hello, ${snapshot.data!.name}');
},
);
}
}
Features #
SyncacheScope #
Provides cache instances to the widget subtree via InheritedWidget:
// Access cache anywhere in the subtree
final cache = SyncacheScope.of<User>(context);
// Access the lifecycle observer
final observer = SyncacheScope.observerOf<User>(context);
MultiSyncacheScope #
Provide multiple cache types without deep nesting:
MultiSyncacheScope(
network: flutterNetwork,
configs: [
SyncacheScopeConfig<User>(userCache),
SyncacheScopeConfig<Post>(postCache),
SyncacheScopeConfig<Settings>(settingsCache),
],
child: const MyApp(),
);
CacheBuilder #
StreamBuilder-style widget for reactive cache display:
CacheBuilder<User>(
cacheKey: 'user:123',
fetch: fetchUser,
policy: Policy.staleWhileRefresh,
ttl: const Duration(minutes: 5),
initialData: cachedUser,
buildWhen: (previous, current) => previous?.name != current.name,
builder: (context, snapshot) {
if (!snapshot.hasData) return const SizedBox.shrink();
return Text(snapshot.data!.name);
},
);
CacheConsumer #
Consumer pattern with separate listener for side effects:
CacheConsumer<User>(
cacheKey: 'user:123',
fetch: fetchUser,
listener: (context, snapshot) {
// Handle side effects (e.g., show snackbar, navigate)
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('User updated: ${snapshot.data!.name}')),
);
},
builder: (context, snapshot) {
if (!snapshot.hasData) return const SizedBox.shrink();
return Text(snapshot.data!.name);
},
);
FlutterNetwork #
Connectivity detection using connectivity_plus:
final network = FlutterNetwork(
debounceDuration: Duration(milliseconds: 500),
);
await network.initialize();
// Check current status
print('Online: ${network.isOnline}');
// Listen to connectivity changes
network.onConnectivityChanged.listen((isOnline) {
print('Connectivity changed: $isOnline');
});
Lifecycle Management #
Configure automatic refetching on app resume and connectivity restoration:
SyncacheScope<User>(
cache: userCache,
network: network,
config: LifecycleConfig(
refetchOnResume: true,
refetchOnResumeMinDuration: const Duration(minutes: 1),
refetchOnReconnect: true,
onRefetchError: (key, error, stackTrace) {
logger.warning('Failed to refetch $key: $error');
},
),
child: const MyApp(),
);
SyncacheValueListenable #
Use with ValueListenableBuilder for more control:
final listenable = cache.toValueListenable(
key: 'user:123',
fetch: fetchUser,
);
ValueListenableBuilder<AsyncSnapshot<User>>(
valueListenable: listenable,
builder: (context, snapshot, child) {
if (!snapshot.hasData) return const SizedBox.shrink();
return Text(snapshot.data!.name);
},
);
// Trigger manual refresh
await listenable.refresh();
// Don't forget to dispose
listenable.dispose();
API Reference #
Widgets #
| Widget | Description |
|---|---|
SyncacheScope<T> |
InheritedWidget for cache dependency injection |
MultiSyncacheScope |
Provides multiple cache types without nesting |
CacheBuilder<T> |
StreamBuilder-style reactive cache display |
CacheConsumer<T> |
Consumer pattern with listener callback |
Classes #
| Class | Description |
|---|---|
FlutterNetwork |
Connectivity detection with debouncing |
SyncacheLifecycleObserver<T> |
App lifecycle and reconnect handling |
LifecycleConfig |
Configuration for lifecycle behavior |
SyncacheValueListenable<T> |
ValueListenable wrapper for cache streams |
WatcherRegistration<T> |
Registration info for lifecycle-based refetching |
Requirements #
- Dart SDK: ^3.0.0
- Flutter: >=3.10.0
- syncache: ^0.6.0
- connectivity_plus: ^7.0.0
License #
MIT License - see LICENSE for details.