better_shared_preferences 0.0.1
better_shared_preferences: ^0.0.1 copied to clipboard
Typed reactive wrapper around shared_preferences for primitives, lists, and JSON objects.
better_shared_preferences #
Thin typed wrapper around shared_preferences: primitives and JSON objects with optional reactive updates via streams.
Features #
- Typed accessors for
String,int,bool,double, andList<String> - Nullable prefs (
Pref<T?>) when the key may be absent - JSON-backed objects via
ObjectPref<T>(fromJson/toJson) watch()streams per key (initial value plus updates afterset/remove)- Cache keyed by preference key with runtime validation: requesting the same key with a different type throws
StateErrorinstead of failing later with a cast error - Invalid JSON for object prefs falls back to
defaultValue(no crash fromjsonDecode/fromJson)
Getting started #
Add the dependency (after publishing or via path/Git):
dependencies:
better_shared_preferences: ^0.0.1
Initialize once (typically after WidgetsFlutterBinding.ensureInitialized()):
final prefs = await BetterPrefs.init();
Always call dispose() when the owning object is torn down if you subscribed to streams or want to drop controllers cleanly:
prefs.dispose();
After dispose(), any use of prefs throws StateError.
Usage #
Primitives #
final prefs = await BetterPrefs.init();
final username = prefs.value<String>('username', defaultValue: '');
await username.set('Ada');
final darkMode = prefs.value<bool>('dark_mode', defaultValue: false);
final tags = prefs.value<List<String>>('tags', defaultValue: []);
await tags.set(['dart', 'flutter']);
await username.remove(); // removes only this pref's key
Nullable values #
final token = prefs.nullable<String>('auth_token');
// Missing key → get() returns null
await token.set('secret'); // stored when supported types are used
Note: Pref<T?>.set(null) is not supported by the underlying storage helper today; use remove() to clear the key.
Reactive updates #
final counter = prefs.value<int>('counter', defaultValue: 0);
counter.watch().listen((value) {
print('counter = $value');
});
await counter.set(counter.get() + 1);
JSON objects #
class Profile {
Profile({required this.name});
final String name;
Map<String, dynamic> toJson() => {'name': name};
factory Profile.fromJson(Map<String, dynamic> json) =>
Profile(name: json['name'] as String);
}
final prefs = await BetterPrefs.init();
final profilePref = prefs.object<Profile>(
'profile',
defaultValue: Profile(name: 'guest'),
fromJson: Profile.fromJson,
toJson: (p) => p.toJson(),
);
await profilePref.set(Profile(name: 'Kim'));
final current = profilePref.get(); // Profile or default if corrupt JSON
Same key, wrong type #
final prefs = await BetterPrefs.init();
prefs.value<int>('mode', defaultValue: 0);
// Throws StateError — key already bound to non-nullable int
prefs.value<String>('mode', defaultValue: '');
Example app #
See the example/ directory for a minimal Flutter app (Increment + StreamBuilder on watch()).
Run from the repo root:
cd example && flutter run
Testing your app / this package #
In tests, mock in-memory prefs before BetterPrefs.init():
import 'package:flutter_test/flutter_test.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:better_shared_preferences/better_shared_preferences.dart';
void main() {
TestWidgetsFlutterBinding.ensureInitialized();
test('reads default', () async {
SharedPreferences.setMockInitialValues({});
final prefs = await BetterPrefs.init();
expect(prefs.value<int>('x', defaultValue: 42).get(), 42);
});
}
Package tests live under test/ — run:
flutter test
Limitations #
- Stored types must match what
shared_preferencessupports; unsupported runtime types passed tosetthrowUnsupportedError. - Object prefs are stored as a JSON string under a single key.
Contributing #
Issues and pull requests are welcome. Please run flutter analyze and flutter test before submitting changes.