This article by Jian Yue SimpRead transcoding, original address www.raywenderlich.com

This chapter will teach you how to save simple data to local storage on your device, on Android and…… .

Imagine that. You’re looking through the menu and you find a dish you like. You’re in a hurry and want to save it for later review. Can you build a Flutter app that does this? Of course you can! Read on to learn how.

In this chapter, your goal is to learn how to use the Shared_Preferences plug-in to save important information to your device.

You’ll start with a new project and display three tabs at the bottom of the screen for three different views :Recipes, Bookmarks and Bags.

The first screen is where you search for recipes you want to prepare. Once you’ve found a recipe you like, just bookmark it and the app will add the recipe to your Bookmarks page, along with all the ingredients you need to add to your shopping list. You’ll use web apis to search for recipes and store your favorites in a local database.

The finished application will look like.

This shows the Recipes TAB you got when you searched pasta. This is as simple as typing in the search text field and pressing the search icon. The application stores your search term history in a combo box to the right of the text field.

When you click on a card, you see something similar.

To save a recipe, just click the Bookmark button. When you browse to the Bookmark TAB, you will see that the recipe has been saved.

If you don’t want the recipe anymore, swipe left or right and you’ll see a delete button that allows you to delete it from the list of bookmarked recipes.

The TAB on Saturday shows the ingredients you need to make the recipe on your bookmark.

You will build this application in the next few chapters. In this chapter, you will use shared Preferences to store simple data, such as selected tags, as well as cache items searched for in recipe tags.

By the end of this chapter, you will know.

  • What is shared Preferences?
  • How to use the Shared_Preferences plug-in to save and retrieve objects.

Now that you know what your goals are, it’s time to get started!

Begin to use

Open the startup project for this chapter in Android Studio, run flutter Pub get if necessary, and then run the application.

Note the three tabs at the bottom — each TAB shows a different screen when you click on it. Currently, only the recipe UI is displayed. It looks something like this.

App libraries

The startup project includes the following libraries in pubspec.yaml.

dependencies:
  ...
  cached_network_image: ^2.5. 0
  flutter_slidable: ^0.57.
  flutter_svg: ^0.193.


Copy the code

Here’s what they help you do.

Cached_network_image: Downloads and caches images that you will use in your application. Flutter_slidable: Build a widget that lets users swipe cards left and right to perform different actions, such as deleting saved recipes. Flutter_svg: Loads SVG images without using a program to convert them into vector files.

Now that you’ve taken a look at these libraries, before you start coding your application, take a moment to think about how you’ll save your data.

Save the data

There are three main ways to save data to your device.

  1. Writes formatted data, such as JSON, to a file.
  2. Use a library or plug-in to write simple data to a shared location.
  3. Use an SQLite database.

Writing data to a file is simple, but it requires you to read and write data in the right format and order.

You can also use a library or plugin to write simple data to a shared location managed by the platform, such as iOS and Android. This is what you will do in this chapter.

For more complex data, you can save the information to a local database. You will learn more about this in future chapters.

Why save small pieces of data?

There are many reasons to keep small pieces of data. For example, you can save the user ID when the user logs in — or whether the user logged in at all. You can also save the user’s entry status, or save the user’s data on their bookmarks for later reference.

Note that this simple data stored on shared Prefesrence is lost when the user uninstalls the application.

Shared_preferences plug-in

Shared_preferences is a Flutter plugin that allows you to save data in key-value format so that you can easily retrieve it later. Behind the scenes, it uses the appropriate SharedPreferences on Android and similar UserDefaults on iOS.

For this application, you will learn to use the plugin to save the search terms entered by the user as well as the currently selected tags.

One of the benefits of this plug-in is that it doesn’t require any setup or configuration. By creating an instance of the plug-in, you can retrieve and save data.

Pay attention to. The Shared_Preferences plug-in gives you a quick way to save and retrieve data, but it only supports saving simple properties such as strings, numbers, and Booleers.

In later chapters, you’ll learn about the alternatives you can use when you want to save complex data.

Please note that shared_Preferences are not suitable for storing sensitive data. To store passwords or access tokens, check out the Android Keystore and iOS Keychain services, or consider using the Flutter_secure_storage plug-in.

To use Shared_Preferences, you need to add it as a dependency first. Open pubspec.yaml, under the flutter_SVG library, and add.

Shared_preferences: ^ at 2.0.5Copy the code

Make sure you indent the same as the other libraries.

Now click the Pub Get button to Get the Shared_Preferences library.

You can also run pub get from the command line.

flutter pub get


Copy the code

You are now ready to store your data. You’ll start by saving users’ searches so they can easily select them again in the future.

Save UI state

You will use shared_Preferences in this section to save the list of saved searches. Later, you’ll also save the TAB selected by the user, so the app stays open all the way up to that TAB.

You’ll start by preparing your search to store this information.

Add an entry to the search list

First, you change the user interface so that when the user presses the search icon, the application adds the search item to the search list.

Open UI /recipes/recipe_list.dart and

import 'package:flutter/material.dart';


Copy the code

Add:

import 'package:shared_preferences/shared_preferences.dart';
import '... /widgets/custom_dropdown.dart';
import '... /colors.dart';


Copy the code

This imports the Shared_Preferences plug-in, a custom widget that displays a drop-down menu, and a helper class that sets colors.

Next, you’ll give each search term a unique key. After.

class _RecipeListState extends State<RecipeList> {


Copy the code

Add.

static const String prefSearchKey = 'previousSearches';


Copy the code

All preferences need to use a unique key, otherwise they will be overwritten. In this case, you just define a constant for the preference key.

And then, after this variable.

bool inErrorState = false;


Copy the code

Add.

List<String> previousSearches = <String> [];Copy the code

This clears the way for you to save your users’ previous searches and keep track of their current searches.

Run the code in the background

To understand the code you’re going to add next, you need to look at running code in the background.

Most modern UIs have a main thread that runs the UI code. Any code that takes a long time needs to run in a different thread or process so it doesn’t block the UI. Dart uses a javascript-like technology to do this. The language includes these two keywords.

  • async
  • await

Async marks a method or part of code as asynchronous. You then use the await keyword in this method to wait until an asynchronous process completes in the background.

Dart also has a class called Future, which indicates that the method promises a Future result. < SharedPreferences SharedPreferences. GetInstance () returns the Future >, you use it to retrieve the SharedPreferences instance of the class. And you’ll see how that works.

Save previous searches

Now that you’ve laid some foundation, you’re ready to implement save search.

Again in recipe_list.dart, after dispose(), add the following methods.

void savePreviousSearches() async {
  / / 1
  final prefs = await SharedPreferences.getInstance();
  / / 2
  prefs.setStringList(prefSearchKey, previousSearches);
}


Copy the code

Here, you use the async keyword to indicate that the method will run asynchronously. It also

  1. useawaitKeyword to waitSharedPreferencesThe instance.
  2. useprefSearchKeyKey to save a list of previous searches.

Next, add the following methods.

void getPreviousSearches() async {
  / / 1
  final prefs = await SharedPreferences.getInstance();
  / / 2
  if (prefs.containsKey(prefSearchKey)) {
    / / 3
    previousSearches = prefs.getStringList(prefSearchKey);
    / / 4
    if (previousSearches == null) {
      previousSearches = <String> []; }}}Copy the code

This method is also asynchronous. Here you are

  1. useawaitKeyword to wait for oneSharedPreferencesThe instance.
  2. Check to see if the preferences for your saved lists already exist.
  3. Gets a list of previous searches.
  4. If the list is’ empty ‘, an empty list is initialized.

Finally, add after super.initstate () in initState().

getPreviousSearches();


Copy the code

This will load all previous searches when the user restarts the application.

Add a search function

To perform the search, you need to clear any variables and save the new search value. This method does not do the actual search yet. This is done by adding the startSearch() method after the _buildSearchCard() method.

void startSearch(String value) {
  / / 1
  setState(() {
    / / 2
    currentSearchList.clear();
    currentCount = 0;
    currentEndPosition = pageCount;
    currentStartPosition = 0;
    hasMore = true;
    / / 3
    if(! previousSearches.contains(value)) {/ / 4
      previousSearches.add(value);
      / / 5savePreviousSearches(); }}); }Copy the code

In this method, you.

  1. Tell the system to redraw the widget by calling setState().

  2. Clears the current search list and resets the count, start, and end positions.

  3. Check to ensure that the search text has not been added to the previous search list.

  4. Adds the search term to the previous search list.

  5. Save previous searches.

Add a search button

Next, you’ll add a search button that saves the keyword each time the user performs a search.

In _buildSearchCard(), replace const Icon(icons.search) with the following.

IconButton(
  icon: const Icon(Icons.search),
  / / 1
  onPressed: () {
    / / 2
    startSearch(searchTextController.text);
    / / 3
    final currentFocus = FocusScope.of(context);
    if(! currentFocus.hasPrimaryFocus) { currentFocus.unfocus(); }}),Copy the code

This replaces the icon with an IconButton that users can click to search for.

  1. addonPressedTo handle the click event.
  2. Start the search using the current search text.
  3. Through the use ofFocusScopeClass to hide the keyboard.

Next, Replace everything between // *** Start Replace and // *** End Replace with.

Expanded(
  / / 3
  child: TextField(
    decoration: const InputDecoration(
      border: InputBorder.none, hintText: 'Search'),
    autofocus: false./ / 4
    textInputAction: TextInputAction.done,
    / / 5
    onSubmitted: (value) {
      if(! previousSearches.contains(value)) { previousSearches.add(value); savePreviousSearches(); } }, controller: searchTextController, )),/ / 6
PopupMenuButton<String>(
  icon: const Icon(
    Icons.arrow_drop_down,
    color: lightGrey,
  ),
  / / 7
  onSelected: (String value) {
    searchTextController.text = value;
    startSearch(searchTextController.text);
  },
  itemBuilder: (BuildContext context) {
    / / 8
    return previousSearches
      .map<CustomDropdownMenuItem<String> > ((String value) {
        return CustomDropdownMenuItem<String>(
          text: value,
          value: value,
           callback: () {
              setState(() {
                / / 9previousSearches.remove(value); Navigator.pop(context); }); }); }).toList(); },),Copy the code

In this code, you.

  1. Add a TextField to enter your search query.

  2. Set the keyboard action to textinputAction.done. This closes the keyboard when the user presses the finish button.

  3. When the user is finished typing the text, the search is saved.

  4. Create a PopupMenuButton to display previous searches.

  5. When the user selects an item from a previous search, a new search is started.

  6. Create a custom drop-down menu list (see widgets/custom_dropdown.dart) to display previous searches.

  7. If the X icon is pressed, delete the search from the previous search and close the pop-up menu.

To display the previous text search list, you use a text field with a drop-down menu. This is a line with a text field ‘and a custom drop-down menu item’. This menu item displays the search term and the icon to the right. It’s going to look something like this.

Clicking X will remove the corresponding item from the list.

Test application

Now it’s time to test the application. Because you added a new dependency, exit the running instance and run it again (note that you don’t always need to reboot when adding dependencies). You’ll see something like this.

PopupMenuButton displays a menu when clicked and calls the onSelected() method when the user selects a menu item.

Enter a food item, such as pasta, and make sure that when you click the search button, the app adds your search item to the drop-down list.

Don’t worry about progress circles running – that happens when there is no data. Your application should look like this when you click the drop-down arrow.

Now stop the application by clicking the red Stop button.

Run the application again and click the drop-down button. The pasta entry is right there. It’s time to celebrate :]

The next step is to save the selected label in the same way.

Save the selected label

In this section, you will use shared_preferences to save the current UI tag that the user has navigated to.

Open main_screen.dart and add the following imports.

import 'package:shared_preferences/shared_preferences.dart';


Copy the code

The next.

List<Widget> pageList = <Widget>[];


Copy the code

Then add:

static const String prefSelectedIndexKey = 'selectedIndex';


Copy the code

This is the constant you use to select the index preference key.

Next, add the new method after initState().

void saveCurrentIndex() async {
  / / 1
  final prefs = await SharedPreferences.getInstance();
  / / 2
  prefs.setInt(prefSelectedIndexKey, _selectedIndex);
}



Copy the code

Here:

  1. useawaitKeyword to wait for an instance of a shared preference plug-in.
  2. Saves the selected index as an integer.

Now add getCurrentIndex().

void getCurrentIndex() async {
  / / 1
  final prefs = await SharedPreferences.getInstance();
  / / 2
  if (prefs.containsKey(prefSelectedIndexKey)) {
    / / 3setState(() { _selectedIndex = prefs.getInt(prefSelectedIndexKey); }); }}Copy the code

With this code, you.

  1. useawaitKeyword to wait for an instance of a shared preference plug-in.
  2. Check if your current index preferences already exist.
  3. Gets the current index and updates the status accordingly.

Now add the following as the last line in initState().

getCurrentIndex();


Copy the code

This will retrieve the currently selected index when the page loads.

Finally, when the user clicks on a TAB, you need to call saveCurrentIndex().

To do this, add the following content to the end of _onItemTapped().

saveCurrentIndex();


Copy the code

This will save the current index each time the user selects a different label.

Now, get the application up and running, and select the second or third TAB.

Exit the application and run it again to ensure that the application starts with the saved index.

At this point, your app should display a list of previously searched items and also take you to the last TAB you selected when you launch the app again. Here’s an example.

Congratulations to you! You have saved status for both the current TAB and the user’s previous searches.

The key point

  • There are several ways to store data within an application: in files, shared preferences, and SQLite databases.
  • The shared preference is best used to store simple, primitive key-value pairs, such as strings, numbers, and booleans.
  • An example of using shared preferences is to save a tag that the user is viewing so that the user is brought to the same TAB the next time he or she launches the application.
  • async/awaitKeyword pairs let you run asynchronous code outside of the main UI thread and wait for a response. One example is getting oneSharedPreferencesThe instance.
  • The Shared_Preferences plug-in should not be used to store sensitive data. Instead, consider using the Flutter_secure_storage plug-in.

Where do we go from here?

In this chapter, you learned how to persist simple data types in your application using the Shared_Preferences plug-in.

If you want to learn more about the Android SharedPreferences, please go to the developer.android.com/reference/k… .

For iOS, please check UserDefaults developer.apple.com/documentati… .

In the next chapter, you’ll continue building the same application and learn how to serialize JSON in preparation for retrieving data from the Internet. See you then!


www.deepl.com translation