streaming_shared_preferences 1.0.0-dev copy "streaming_shared_preferences: ^1.0.0-dev" to clipboard
streaming_shared_preferences: ^1.0.0-dev copied to clipboard

outdated

A reactive, Stream-based wrapper for SharedPreferences

streaming_shared_preferences - (dev preview) #

A reactive key-value store for Flutter projects.

It wraps shared_preferences with a Stream based layer, allowing you to listen to changes in the underlying values. It serves as a great companion to the StreamBuilder widget or as a reactive data source that you can share between your BLoCs to keep your UI up to date.

Simple usage example #

To get a hold of StreamingSharedPreferences, await on instance:

import 'package:streaming_shared_preferences/streaming_shared_preferences.dart';

...
final preferences = await StreamingSharedPreferences.instance;

The public API follows the same naming convention as shared_preferences does, but with a little twist - every getter returns a Preference object, which is a Stream!

For example, here's how you would get and listen to changes in an int with the key "counter":

// Provide a default value of 0 in case "counter" is null.
final counter = preferences.getInt('counter', defaultsTo: 0);

// "counter" is a Stream - it can do anything a Stream can!
counter.listen((value) {
  print(value);
});

// Same as preferences.setInt('counter', <value>), but no need to provide a key here.
counter.set(1);
counter.set(2);
counter.set(3);

// Obtain current value synchronously. In this case, "currentValue" is now 3.
final currentValue = counter.value();

Assuming that there's no previously stored value for counter, the above example will print 0, 1, 2 and 3 to the console.

Using StreamingSharedPreferences with the StreamBuilder widget #

Here's the standard counter app that you get when creating a Flutter project, but with a twist.

The difference to the regular one is that the value of counter is persisted locally. This means that the state will not get lost between app restarts.

class MyHomePage extends StatefulWidget {
  MyHomePage(this.preferences);
  final StreamingSharedPreferences preferences;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  Preference<int> _counter;

  @override
  void initState() {
    super.initState();
    _counter = widget.preferences.getInt('counter', defaultsTo: 0);
  }

  @override
  Widget build(BuildContext context) {
    return Column(
      mainAxisAlignment: MainAxisAlignment.center,
      children: [
        Text('You have pushed the button this many times:'),
        StreamBuilder<int>(
          stream: _counter,
          builder: (context, snapshot) {
            return Text(
              '${snapshot.data}',
              style: Theme.of(context).textTheme.display1,
            );
          },
        ),
        RaisedButton(
          onPressed: () {
            final currentValue = _counter.value();
            _counter.set(currentValue + 1);
          },
          child: Text('Increment!'),
        ),
      ],
    );
  }
}

There's one thing worth noting here: do NOT pass preferences.getInt(..) to a StreamBuilder directly. Cache it instead.

To illustrate, DO:

class _MyHomePageState extends State<MyHomePage> {
  Preference<int> _counter;

  @override
  void initState() {
    super.initState();
    _counter = widget.preferences.getInt('counter', defaultsTo: 0);
  }

  @override
  Widget build(BuildContext context) {
    return StreamBuilder(
      stream: _counter, // Good :-)
      builder: (context, snapshot) { .. },
    );
  }
}

DO NOT:


class _MyHomePageState extends State<MyHomePage> {
  @override
  Widget build(BuildContext context) {
    return StreamBuilder(
      stream: widget.preferences.getInt('counter', defaultsTo: 0), // BAD! >:-(
      builder: (context, snapshot) { .. },
    );
  }
}