Chidume Nnamdi I'm a software engineer with over six years of experience. I've worked with different stacks, including WAMP, MERN, and MEAN. My language of choice is JavaScript; frameworks are Angular and Node.js.

Using SharedPreferences in Flutter to store data locally

7 min read 2223

Using SharedPreferences in Flutter to Store Data Locally

There may come a time when you want to persist data in your Flutter app so you can reuse it later. A common use case for this functionality is storing login credentials to be recalled the next time the user launches the app.

With SharedPreferences, you can configure your Flutter app to remember the data even after the user terminates their activity. SharedPreferences can be used to store critical data such as passwords, tokens, and complex relational data.

In this tutorial, we’ll demonstrate how to persist and modify data using SharedPreferences in a Flutter app. We’ll cover the following with practical examples:

What is SharedPreferences in Flutter?

SharedPreferences is what Android and iOS apps use to store simple data in an allocated space. This data exists even when the app is shut down and starts up again; we can still retrieve the value as it was.

The data stored in SharedPreferences can be edited and deleted. SharedPreferences stores the data in a key-value pair.

To use SharedPreferences in Flutter, a plugin called shared_preferences enables us to store data. The plugin wraps NSUserDefaults on iOS and SharedPreferences on Android.

Scaffolding a Flutter project

Let’s walk through how to scaffold a Flutter project, add the shared_preferences plugin to a Flutter project, and the methods exposed to us by the plugin.

You’ll need to have some tools and binaries already installed on your machine, including the Flutter SDK and Android Studio.

Flutter SDK

To install the Flutter SDK on our machine, you need to choose your Flutter binary as per your machine below:

After the installation, you will have the Flutter CLI available globally in your system. Run the below command to test this:

➜  flutter --version

Flutter 2.0.6 • channel stable • https://github.com/flutter/flutter.git
Framework • revision 1d9032c7e1 (3 months ago) • 2021-04-29 17:37:58 -0700
Engine • revision 05e680e202
Tools • Dart 2.12.3

Your version may be different from mine but you should be able to verify that the Flutter SDK was successfully installed.

Android Studio

We’ll be developing for the Android OS and we’ll need an emulator to test our apps on the run. Android Studio is the official IDE/SDK used for building, testing, and publishing Android apps.
Head to the official website to download and install Android Studio on your machine.

To use Android Studio to develop Flutter projects, you’ll need to install the following plugins:

To scaffold a Flutter project, run the following command:

flutter create shared_pref

This command creates a folder, shared_pref, and places a Flutter project inside it. You can open the project using VS Code or Android Studio.

Installing shared_preferences

Now that we have the Flutter SDK ready and set, it’s time to install the shared_preferences plugin.

Open the pubspec.yaml file and add shared_preferences in the dependencies section:

dependencies:
  flutter:
    sdk: flutter
  shared_preferences:

This will install the latest version of the dependency.

To use the shared_preferences plugin, we have to import it into our file:

import 'package:shared_preferences/shared_preferences.dart';

The shared_preferences plugin exports a SharedPreferences class, which has methods that can be used to set data of various primitive types in SharedPreferences. It has a method, getInstance, which is used to create an instance of a SharedPreferences.



SharedPreferences prefs = await SharedPreferences.getInstance();

The getInstance creates and returns a SharedPreferences instance. The prefs holds the instance of SharedPreferences.

shared_preferences methods

In this section, we’ll demonstrate how to add data to and get, edit, and delete data from SharedPreferences.

Adding data

It’s possible to add data of primitive types to SharedPreferences. We can add the following primitive types:

  • int
  • string
  • bool
  • double

Each primitive type has its corresponding setter method. (Note: The key of the key-value pair is in string.)

Add int

prefs.setInt('counter', 1);

This adds an int, 1, to the counter table of SharedPreferences.

Add string

prefs.setString('counter', "yes");

This adds a string, "yes", to the counter.

Add bool

prefs.setBool('counter', true);

This adds a bool, true, to the counter.

Add double

prefs.setDouble('counter', 10.2);

This adds a double value, 10.2, to the counter.

Retrieving data

Now, let’s see how we can retrieve data from SharedPreferences. As we have setter methods for the primitive types so we have getter methods for retrieving data.


More great articles from LogRocket:


Get int data

int value = prefs.getInt('counter');

The getInt method is used to retrieve an int value from the SharedPreferences.

value // 1

Get bool data

bool value = prefs.getBool('counter');

This method getBool returns a boolean value from the SharedPreferences.

value // true

Get double data

double value = prefs.getDouble('counter');

The getDouble method returns a double value from the SharedPreferences.

value // 10.2

Get string data

string value = prefs.getString('counter');

The getString method returns a string value from the SharedPreferences.

value // "yes"

null value

In a case where the data is not present in the SharedPreferences, a null value is returned:

prefs.getInt("_counter")
// null

prefs.getBool("_counter")
// null

prefs.getString("_counter")
// null

prefs.getDouble("_counter")
// null

Deleting data

To remove data from the SharedPreferences, we’ll use the remove method. The key of the data is passed to the .remove method so the key-value pair data in the SharedPreferences is deleted.

prefs.remove("counter");

Here, the counter in the SharedPreferences is deleted.

Verifying that data exists

We can check in SharedPreferences to see whether data exists before we either read or write. To do this, we’ll use the containsKey method.

The containsKey method accepts the key of the data in its arg and uses it to check whether the key exists in SharedPreferences.

The method returns a bool, true or false:

prefs.containsKey("counter")
// true

In the above example, counter exists in the SharedPreferences. That’s why it returns true.

prefs.containsKey("_counter")
// false

_counter does not exist, so it returns false.

Using shared_preferences in Flutter

By default, Flutter adds a counter project whenever you scaffold a new project. This counter project enables us to increment a counter when a FloatingActionButton is pressed. The current state of the counter is displayed as it is being increased.

import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);

  final String title;

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

class _MyHomePageState extends State<MyHomePage> {
  int _counter = 0;

  void _incrementCounter() {
    setState(() {
      _counter++;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text(
              'You have pushed the button this many times:',
            ),
            Text(
              '$_counter',
              style: Theme.of(context).textTheme.headline4,
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _incrementCounter,
        tooltip: 'Increment',
        child: Icon(Icons.add),
      ), // This trailing comma makes auto-formatting nicer for build methods.
    );
  }
}

The counter reverts to 0 when the app is destroyed or closed. We’ll use SharedPreferences to persist the state of the counter so the counter value begins from where it was before the app was shut down.

Let’s do it.

First, import the shared_preferences plugin:

import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';

Next, add an initState lifecycle method in the MyHomePageState widget. This lifecycle method is called when a stateful widget is being initialized.

Here, we’ll load the counter from SharedPreferences. If present, we’ll make it the counter value. If not, we assign 0 to the counter:

  void loadCounter() async {
    SharedPreferences prefs = await SharedPreferences.getInstance();
    setState(() {
      _counter = (prefs.getInt('counter') ?? 0);
    });
  }

  @override
  void initState() {
    super.initState();
    loadCounter();
  }

Now let’s make the _incrementCounter function an async function. Inside it, we’ll get the counter from SharedPreferences, increment it, then set the counter with the increment and also set the increment in the SharedPreferences.

  void _incrementCounter() async {
    SharedPreferences prefs = await SharedPreferences.getInstance();
    setState(() {
      _counter = ((prefs.getInt('counter') ?? 0) + 1);
      prefs.setInt('counter', _counter);
    });
  }

Now our Flutter application can remember the last value of the counter when shut down and restarted.

Testing our Flutter app

First, let’s start our app:

Flutter SharedPreferences Demo: Start App

Increment to seven:

Flutter SharedPreferences Demo: Increment to 3 Flutter SharedPreferences Demo: Increment to 7

Now let’s try killing the app:

Flutter SharedPreferences Demo: Killing the App

Upon restarting the app, the button count should still display as 7.

Flutter SharedPreferences Demo: Restart App Flutter SharedPreferences Demo: Increment to 7

Implementing a splash screen using SharedPreferences

We can use SharedPreferences to implement a splash screen in Flutter.

A splash screen appears when an app is launched for the first time and does not appear again when the app is launched subsequently.

Let’s say we have an app with two screens: ProfileScreen and SplashScreen. We’ll hook into the initState method in the MyApp widget. From there, we’ll always check for a data in the SharedPreferences — let’s say newLaunch. If this newLaunch is true, the SplashScreen is shown and after some time the ProfileScreen is shown. The SplashScreen will reset the newLaunch to false.

If the newLaunch is false, the SplashScreen is skipped and the ProfileScreen is shown.

Let’s code our splash and profile screens!

Create a folder, screens, inside the lib folder:

mkdir lib/screens
touch lib/screens/ProfileScreen.dart lib/screens/SplashScreen.dart

Let’s edit the MyApp widget as follows:

import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'screens/ProfileScreen.dart';
import 'screens/SplashScreen.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
        title: 'SharedPreferences Demo',
        theme: ThemeData(
          primarySwatch: Colors.blue,
        ),
        home: LoadPage() //MyHomePage(title: 'SharedPreferences Demo'),
        );
  }
}

class LoadPage extends StatefulWidget {
  LoadPage({Key key}) : super(key: key);

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

class LoadPageState extends State {
  var newLaunch;

  @override
  void initState() {
    super.initState();
    loadNewLaunch();
  }

  loadNewLaunch() async {
    SharedPreferences prefs = await SharedPreferences.getInstance();
    setState(() {
      bool _newLaunch = ((prefs.getBool('newLaunch') ?? true));
      newLaunch = _newLaunch;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(body: newLaunch ? SplashScreen() : ProfileScreen());
  }
}

We have LoadPage widget and its state widget, LoadPageState. In LoadPageState, we have a method, loadNewLaunch, which checks to get the newLaunch data from the SharedPrefs and assigns it to the newLaunch state variable.

In the build method of the LoadPageState, the widget checks the newLaunch state. If the state is true, that means the app is launching for the very first time and the SplashScreen widget is shown. If not true, the ProfileScreen is shown.

Let’s code the SplashScreen widget:

import 'dart:async';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:flutter/material.dart';
import 'ProfileScreen.dart';

class SplashScreen extends StatefulWidget {
  SplashScreen({Key key}) : super(key: key);

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

class _SplashScreenState extends State<SplashScreen> {
  resetNewLaunch() async {
    SharedPreferences prefs = await SharedPreferences.getInstance();
    if (prefs.containsKey("newLaunch")) {
      prefs.setBool('newLaunch', false);
    } else {
      prefs.setBool('newLaunch', false);
    }
  }

  @override
  void initState() {
    super.initState();
    Timer(
        Duration(seconds: 3),
        () => Navigator.pushReplacement(context,
                MaterialPageRoute(builder: (context) {
              resetNewLaunch();
              return ProfileScreen();
            })));
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        body: Container(
            color: Colors.blue,
            child: Center(
              child: Column(
                mainAxisAlignment: MainAxisAlignment.center,
                children: <Widget>[
                  Text('Splash Screen',
                      style: new TextStyle(color: Colors.white, fontSize: 40)),
                ],
              ),
        )
      )
    );
  }
}

The resetNewLaunch method sets the newLaunch data in the SharedPrefs to false.

In the initState method, SplashScreen calls the resetNewLaunch method to set the newLaunch data to false in the SharedPrefs. This will cause the app to only show the ProfileScreen when the app is launched subsequently.

The timer code waits for three seconds before the ProfileScreen is shown.

Now let’s code the ProfileScreen:

import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';

class ProfileScreen extends StatefulWidget {
  ProfileScreen({Key key}) : super(key: key);

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

class _ProfileScreenState extends State<ProfileScreen> {
  clearSharedPrefs() async {
    SharedPreferences prefs = await SharedPreferences.getInstance();
    prefs.remove('newLaunch');
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: Text("Profile"),
        ),
        body: Container(
          child: Center(
            child: Column(
              mainAxisAlignment: MainAxisAlignment.center,
              children: <Widget>[
                Text('Profile Screen', style: new TextStyle(fontSize: 40)),
                RaisedButton(
                  child: Text("Clear SharedPrefs"),
                  onPressed: clearSharedPrefs,
                )
              ],
            ),
          ),
        ));
  }
}

Nothing much to go over here. We have a Clear SharedPrefs button, which clears the newLaunch data in the SharedPrefs. This action will make the app show the SplashScreen the next time it is launched.

Testing our splash screen

The splash and profile screens should look as follows on the first launch after installation:

Flutter SharedPreferences Demo: Splash Screen on App Launch Flutter SharedPreferences Demo: Profile Screen at Launch

SplashScreen shows first, followed by the ProfileScreen.

Subsequent launches should display the following screens:

Flutter SharedPreferences Demo: Profile Screen Upon Subsequent Launch Flutter SharedPreferences Demo: Profile Screen Upon Subsequent Launch Flutter SharedPreferences Demo: Profile Screen Upon Subsequent Launch

SplashScreen will never appear again, while the ProfileScreen appears straight.

Conclusion

In this tutorial, we covered what SharedPreferences is and how it is used in Android and iOS applications. We also introduced the shared_preferences plugin and learned how to set up Flutter with SharedPreferences.

Next, we learned how to import the shared_preferences plugin, walked through how to initialize its instance, and reviewed its methods and what all of them do. We modified a normal Flutter counter project to show how to use the shared_preferences plugin to persist the counter value and retrieve it after the app has been killed and restarted.

The source code for all the examples in this tutorial is available on GitHub.

Chidume Nnamdi I'm a software engineer with over six years of experience. I've worked with different stacks, including WAMP, MERN, and MEAN. My language of choice is JavaScript; frameworks are Angular and Node.js.

One Reply to “Using SharedPreferences in Flutter to store data locally”

  1. Thank you very much for your article on using Shared Preferences. This is well written and conveys everything one should learn about this. I found it very useful. Thank you very much.

Leave a Reply