rx_shared_preferences 
Author: Petrus Nguyễn Thái Học
- Shared preference with
rxdartStream observation. - Reactive shared preferences for
Flutter. - Reactive stream wrapper around SharedPreferences.
- This package provides reactive shared preferences interaction with very little code. It is designed specifically to be used with Flutter and Dart.
Buy me a coffee
Liked some of my work? Buy me a coffee (or more likely a beer)
Note
Since version 1.3.4, this package is an extension of rx_storage package.
More details about the returned Stream
-
It's a single-subscription
Stream(i.e. it can only be listened once). -
Streamwill emit the value (nullable) or aTypeErroras its first event when it is listened to. -
It will automatically emit the new value when the value associated with key was changed successfully (it will also emit
nullwhen value associated with key wasremovedor set tonull). -
When value read from Storage has a type other than expected type:
- If value is
null, theStreamwill emitnull(this occurred becausenullcan be cast to any nullable type). - Otherwise, the
Streamwill emit aTypeError.
- If value is
-
Can emit two consecutive data events that are equal. You should use Rx operator like
distinct(more commonly known asdistinctUntilChangedin other Rx implementations) to create aStreamwhere data events are skipped if they are equal to the previous data event.
Key changed |----------K1---K2------K1----K1-----K2---------> time
|
Value stream |-----@----@------------@-----@-----------------> time
| ^
| |
| Listen(key=K1)
|
| @: nullable value or TypeError
Getting Started
In your flutter project, add the dependency to your pubspec.yaml
dependencies:
[...]
rx_shared_preferences: <latest_version>
Usage
1. Import and instantiate
- Import
rx_shared_preferences.
import 'package:rx_shared_preferences/rx_shared_preferences.dart';
- Wrap your
SharedPreferencesin aRxSharedPreferences.
// via constructor.
final rxPrefs = RxSharedPreferences(await SharedPreferences.getInstance()); // use await
final rxPrefs = RxSharedPreferences(SharedPreferences.getInstance()); // await is optional
final rxPrefs = RxSharedPreferences.getInstance(); // default singleton instance
// via extension.
final rxPrefs = (await SharedPreferences.getInstance()).rx; // await is required
NOTE: When using
RxSharedPreferences.getInstance()and extension(await SharedPreferences.getInstance()).rx, to config the logger, you can useRxSharedPreferencesConfigs.loggersetter.
2. Add a logger (optional)
You can pass a logger to the optional parameter of RxSharedPreferences constructor.
The logger will log messages about operations (such as read, write, ...) and stream events.
This package provides two RxSharedPreferencesLoggers:
RxSharedPreferencesDefaultLogger.RxSharedPreferencesEmptyLogger.
final rxPrefs = RxSharedPreferences(
SharedPreferences.getInstance(),
kReleaseMode ? null : RxSharedPreferencesDefaultLogger(),
// disable logging when running in release mode.
);
NOTE: To disable logging when running in release mode, you can pass
nullorconst RxSharedPreferencesEmptyLogger()toRxSharedPreferencesconstructor, or useRxSharedPreferencesConfigs.loggersetter.
NOTE: To prevent printing
↓ Disposed successfully → DisposeBag#....import 'package:disposebag/disposebag.dart' show DisposeBagConfigs; void main() { DisposeBagConfigs.logger = null; }
3. Select stream and observe
- Then, just listen
Streams, transformStreams through operators such asmap,flatMap, etc... - If you need to listen to the
Streammany times, you can use broadcast operators such asshare,shareValue,publish,publishValue, etc...
// Listen
rxPrefs.getStringListStream('KEY_LIST').listen(print); // [*]
// Broadcast stream
rxPrefs.getStringListStream('KEY_LIST').share();
rxPrefs.getStringListStream('KEY_LIST').shareValue();
rxPrefs.getStringListStream('KEY_LIST').asBroadcastStream();
// Transform stream
rxPrefs.getIntStream('KEY_INT')
.map((i) => /* Do something cool */)
.where((i) => /* Filtering */)
...
// must **use same rxPrefs** instance when set value and select stream
await rxPrefs.setStringList('KEY_LIST', ['Cool']); // [*] will print ['Cool']
-
In the previous example, we re-used the
RxSharedPreferencesobjectrxPrefsfor all operations. All operations must go through this object in order to correctly notify subscribers. Basically, you must use the sameRxSharedPreferencesinstance when set value and select stream. -
In a Flutter app, you can:
-
Create a global
RxSharedPreferencesinstance. -
Use the default singleton instance via
RxSharedPreferences.getInstance(). -
Use
InheritedWidget/Providerto provide aRxSharedPreferencesinstance (create it inmainfunction) for all widgets (recommended). See example/main.
-
// An example for wrong usage.
rxPrefs1.getStringListStream('KEY_LIST').listen(print); // [*]
rxPrefs2.setStringList('KEY_LIST', ['Cool']); // [*] will not print anything,
// because rxPrefs1 and rxPrefs2 are different instances.
4. Stream APIs and RxStorage APIs
- All
Streams APIs (via extension methods).
Stream<Object?> getObjectStream(String key, [Decoder<Object?>? decoder]);
Stream<bool?> getBoolStream(String key);
Stream<double?> getDoubleStream(String key);
Stream<int?> getIntStream(String key);
Stream<String?> getStringStream(String key);
Stream<List<String>?> getStringListStream(String key);
Stream<Set<String>> getKeysStream();
Future<void> updateBool(String key, Transformer<bool?> transformer);
Future<void> updateDouble(String key, Transformer<double?> transformer);
Future<void> updateInt(String key, Transformer<int?> transformer);
Future<void> updateString(String key, Transformer<String?> transformer);
Future<void> updateStringList(String key, Transformer<List<String>?> transformer);
- All methods from RxStorage
(because
RxSharedPreferencesimplementsRxStorage).
Future<void> update<T extends Object>(String key, Decoder<T?> decoder, Transformer<T?> transformer, Encoder<T?> encoder);
Stream<T?> observe<T extends Object>(String key, Decoder<T?> decoder);
Stream<Map<String, Object?>> observeAll();
Future<void> dispose();
5. Get and set methods likes SharedPreferences
RxSharedPreferencesis like toSharedPreferences, it providesread,writefunctions (via extension methods).
Future<Object?> getObject(String key, [Decoder<Object?>? decoder]);
Future<bool?> getBool(String key);
Future<double?> getDouble(String key);
Future<int?> getInt(String key);
Future<Set<String>> getKeys();
Future<String?> getString(String key);
Future<List<String>?> getStringList(String key);
Future<Map<String, Object?>> reload();
Future<void> setBool(String key, bool? value);
Future<void> setDouble(String key, double? value);
Future<void> setInt(String key, int? value);
Future<void> setString(String key, String? value);
Future<void> setStringList(String key, List<String>? value);
- All methods from Storage
(because
RxSharedPreferencesimplementsStorage).
Future<bool> containsKey(String key);
Future<T?> read<T extends Object>(String key, Decoder<T?> decoder);
Future<Map<String, Object?>> readAll();
Future<void> clear();
Future<void> remove(String key);
Future<void> write<T extends Object>(String key, T? value, Encoder<T?> encoder);
6. Dispose
You can dispose the RxSharedPreferences when it is no longer needed.
Just call rxPrefs.dispose().
Usually, you call this method on dispose method of a Flutter State.
Example demo
Simple authentication app with BLoC rxdart pattern |
Build ListView from Stream using RxSharedPreferences |
Change theme and locale (language) runtime |
|---|---|---|
![]() |
![]() |
![]() |
Features and bugs
Please file feature requests and bugs at the issue tracker.
License
MIT License
Copyright (c) 2019-2024 Petrus Nguyễn Thái Học
Contributors ✨
Thanks goes to these wonderful people (emoji key):
Petrus Nguyễn Thái Học 💻 📖 🚧 |
This project follows the all-contributors specification. Contributions of any kind welcome!
Libraries
- Author: Petrus Nguyễn Thái Học.



