4

I'm new to Flutter and Dart and I have been struggling with saving values in shared preferences to use when my app is restarted. I have successfully stored variables, but I also need object lists to be stored. I know that since shared preferences only accept String lists, I need to convert my object list into a JSON array and when the app is restarted, retrieve this list and convert it to an object list again.

I was able to encode the object list to JSON and I got something like this:

[{name: Rent, amount: 250}, {name: Insurance, amount: 105}]

I achieved this with the following function:

  void SaveLists(key, value) async { //where value is a List<Object>
    final prefs = await SharedPreferences.getInstance();
    List<dynamic> json_list = (value.map((i) => i.toJson())).toList();
    prefs.setStringList(key, json_list); //this line causes the error
    print('$json_list');
  }

The List json_list contains the JSON array that is shown above. However when I try to store it in the shared preferences with prefs.setStringList(key, json_list); I get the following error:

Unhandled Exception: type 'List<dynamic>' is not a subtype of type 'List<String>'

Now, let's say that I somehow store it successfully in shared preferences, how do I convert the JSON array back to a List when called with prefs.getString('key')?

In case you need to see the class, here it is:

import 'dart:convert';
class Random_expenses {

 String name;
 double amount;

 Random_expenses({this.name, this.amount});

 Random_expenses.fromJson(Map<String, dynamic> json)
     : this.name = json['name'],
       this.amount = json['amount'];

 Map<String, dynamic> toJson() =>
     {'name': this.name, 'amount': this.amount};
}

1 Answer 1

5

You can copy paste run full code below
You can save List<RandomExpenses> as a json string with randomExpensesToJson(value)
You can get List<RandomExpenses> with randomExpensesFromJson(keyString)

code snippet

List<RandomExpenses> randomExpensesFromJson(String str) =>
    List<RandomExpenses>.from(
        json.decode(str).map((x) => RandomExpenses.fromJson(x)));

String randomExpensesToJson(List<RandomExpenses> data) =>
    json.encode(List<dynamic>.from(data.map((x) => x.toJson())));
...
void saveData(String key, List<RandomExpenses> value) async {
    final prefs = await SharedPreferences.getInstance();
    prefs.setString(key, randomExpensesToJson(value));
  }

Future<List<RandomExpenses>> getData(String key) async {
  final prefs = await SharedPreferences.getInstance();
  String keyString = prefs.getString(key);
  return Future.value(randomExpensesFromJson(keyString));
}
...
await saveData("key", randomExpensesList);
List<RandomExpenses> list = await getData("key");

print('${list[0].name} ${list[0].amount}');
print('${list[1].name} ${list[1].amount}');

output

I/flutter (24879): Rent 250
I/flutter (24879): Insurance 105

full code

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

List<RandomExpenses> randomExpensesFromJson(String str) =>
    List<RandomExpenses>.from(
        json.decode(str).map((x) => RandomExpenses.fromJson(x)));

String randomExpensesToJson(List<RandomExpenses> data) =>
    json.encode(List<dynamic>.from(data.map((x) => x.toJson())));

class RandomExpenses {
  String name;
  int amount;

  RandomExpenses({
    this.name,
    this.amount,
  });

  factory RandomExpenses.fromJson(Map<String, dynamic> json) => RandomExpenses(
        name: json["name"],
        amount: json["amount"],
      );

  Map<String, dynamic> toJson() => {
        "name": name,
        "amount": amount,
      };
}

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
        visualDensity: VisualDensity.adaptivePlatformDensity,
      ),
      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;
  List<RandomExpenses> randomExpensesList = [
    RandomExpenses(name: "Rent", amount: 250),
    RandomExpenses(name: "Insurance", amount: 105)
  ];

  void saveData(String key, List<RandomExpenses> value) async {
    final prefs = await SharedPreferences.getInstance();
    prefs.setString(key, randomExpensesToJson(value));
  }

  Future<List<RandomExpenses>> getData(String key) async {
    final prefs = await SharedPreferences.getInstance();
    String keyString = prefs.getString(key);
    return Future.value(randomExpensesFromJson(keyString));
  }

  void _incrementCounter() async {
    await saveData("key", randomExpensesList);
    List<RandomExpenses> list = await getData("key");

    print('${list[0].name} ${list[0].amount}');
    print('${list[1].name} ${list[1].amount}');

    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),
      ),
    );
  }
}
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.