Saving Data in Flutter

Jan 31 2024 · Dart 3, Flutter 3.10, Visual Studio Code

Part 3: Reading & Writing Files

16. Using JSON (Part 1)

Episode complete

Play next episode

Next
About this episode
Leave a rating/review
See forum comments
Cinema mode Mark complete Download course materials
Previous episode: 15. Polishing the App Next episode: 17. Using JSON (Part 2)

Get immediate access to this and 4,000+ other videos and books.

Take your career further with a Kodeco Personal Plan. With unlimited access to over 40+ books and 4,000+ professional videos in a single subscription, it's simply the best investment you can make in your development career.

Learn more Already a subscriber? Sign in.

Transcript: 16. Using JSON (Part 1)

There’s a small change we can implement in our app, that will have no impact on the user experience, but can have several benefits for us as developers: it’s leveraging Dart objects and JSON instead of storing simple data in SharedPreferences.
I’ve told you previously, that SharedPreferences only accepts simple data, like strings, numbers, and Booleans, and this is the way we are using SharedPreferences right now.

You may have noticed that complex objects cannot be stored directly in SharedPreferences. But, leveraging JSON, we can not only store complex objects, but also make our code more readable, easier to maintain and less error prone.

Let’s see how we can achieve this. The first step is creating a class that contains all the data we want to store. So, in the lib folder of our project, let’s create a new file, calling it app_settings.dart.

In this new file, let’s create a new class, called AppSettings. At the top of the class, let’s add the four fields we want to store:

class AppSettings { 
  String listName = ''; 
  int calories = 0; 
  bool showFileSize = false; 
  bool showDate = false; 
} 

A string, called listName, an int for the calories a bool for the showFileSize value, and another bool, showdate.

Next let’s create a constructor, that sets all the fields of the class: in order to do that we can leverage the code actions, so that the editor will create the constructor for us. So let’s click on any of the fields, then click the bulb that appears, and select “Generate Constructor”. This builds the constructor for this class automatically.

Good, now comes the interesting part: we want to create a method that transforms this object into JSON, so that we can store it in a single key in SharedPreferences (or Flutter Secure Storage).

In Dart the object that contains key – value pairs, just like json, is a Map object. So let’s create a method that returns a map of type string, dynamic, called toJson. This means that the toJson method returns a map where the keys are strings and the values can be any type (dynamic).

In the method, let’s return a String, dynamic object literal, where the first key, listName, takes the listname value, and let’s repeat for calories, showFileSize, and showDate.

Map<String, dynamic> toJson() { 
    return <String, dynamic>{ 
      'listName': listName, 
      'calories': calories, 
      'showFileSize': showFileSize, 
      'showDate': showDate, 
    }; 
  } 

One last step to complete this class: we want to do the opposite of the toJSON method, which is create an instance of AppSettings from a Map. And for this we’ll create a named constructor, called fromJSON, and using the initializer list syntax (the semi-column), we’ll set each field of the class, starting with listName. Here we’ll use a ternary operator, so if json listName is a string, then we’ll assign it to the listName field as a string (this is needed because the value type of the json object is dynamic, and we wat to parse it as a string). Otherwise (and that means if json listName is not a string, then we’ll set the default value of “My recipes”.
We’ll repeat the same pattern with the remaining fields: so calories, here if json calories is an int, then we’ll assign it, otherwise a default value of 2000.

ShowFileSize: if Json showFileSize is a boolean, we’ll assign it, otherwise true.

And finally we’ll do the same for showDate: if it’s a boolean we’ll assign it, otherwise just true.

AppSettings.fromJson(Map<String, dynamic> json) 
  : listName = json['listName'] is String 
        ? json['listName'] as String 
        : 'My Recipes', 
    calories = json['calories'] is int ? json['calories'] as int : 2000, 
    showFileSize = 
        json['showFileSize'] is bool ? json['showFileSize'] as bool : true, 
    showDate = json['showDate'] is bool ? json['showDate'] as bool : true; 

Right, this AppSettings class is ready! To sum it up: we have created a class, that mirrors the data we want to store locally, and we have a method that from the instance of this class creates a Map, and a constructor that takes a Map and creates an object. This is a very common approach, that you can leverage whenever you want to read and write data in many databases.