skip to Main Content

I have the following class setup. I was able to store the JSON, but I’m having trouble retrieving it.

import 'package:flutter/material.dart';

class SvItem with ChangeNotifier {
  final String id;
  final String meatType;
  final String meatTypeImg;
  final String meatCut;
  final String duration;
  final String temperatur;
  final List<String> instructions;
  final String notes;
  bool isFavorite;

  SvItem({
    required this.id,
    required this.meatType,
    required this.meatTypeImg,
    required this.meatCut,
    required this.duration,
    required this.temperatur,
    required this.instructions,
    required this.notes,
    this.isFavorite = false,
  });

  factory SvItem.fromJson(Map<String, SvItem> json) {
    return SvItem(
      id: "id",
      meatType: "meatType",
      meatTypeImg: "meatTypeImg",
      meatCut: "meatCut",
      duration: "duration",
      temperatur: "temperatur",
      instructions: "instructions" as List<String>,
      notes: "notes",
      isFavorite: "isFavorite" as bool,
    );
  }

  Map<String, dynamic> toJson() {
    return {
      "id": id,
      "meatType": meatType,
      "meatTypeImg": meatTypeImg,
      "meatCut": meatCut,
      "duration": duration,
      "temperatur": temperatur,
      "instructions": instructions,
      "notes": notes,
      "isFavorite": isFavorite
    };
  }
}

With this code, I can save instances of the the custom class in sharedpreferences.

Future saveCustomRecipes(item) async {
  SharedPreferences prefs = await SharedPreferences.getInstance();
  prefs.setString("customRecipesList", jsonEncode(item));
  setState(() {});
}

saveCustomRecipes(customRecipes);

But how can I retrieve it and save it in customRecipes?

I tried the following:

  getCustomRecipesValues() async {
    customRecipes = await getCustomRecipesState();
    setState(() {});
  }

  Future getCustomRecipesState() async {
    final prefs = await SharedPreferences.getInstance();
    var recipeData = prefs.getString("customRecipesList");
    List<SvItem> customRecipes =
        SvItem.fromJson(jsonDecode(recipeData!)) as List<SvItem>;

    print(customRecipes);
    return customRecipes;
  }

But I get an error: [ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: type ‘List’ is not a subtype of type ‘Map<String, dynamic>’

3

Answers


  1. Chosen as BEST ANSWER

    ok I believe I managed to find a solution: This is my SvItem Class:

    class SvItem with ChangeNotifier {
      final String id;
      final String meatType;
      final String meatTypeImg;
      final String meatCut;
      final String duration;
      final String temperatur;
      final List<String> instructions;
      final String notes;
      bool isFavorite;
    
      SvItem({
        required this.id,
        required this.meatType,
        required this.meatTypeImg,
        required this.meatCut,
        required this.duration,
        required this.temperatur,
        required this.instructions,
        required this.notes,
        this.isFavorite = false,
      });
    
      factory SvItem.fromJson(dynamic json) {
        return SvItem(
          id: json["id"] as String,
          meatType: json["meatType"] as String,
          meatTypeImg: json["meatTypeImg"] as String,
          meatCut: json["meatCut"] as String,
          duration: json["duration"] as String,
          temperatur: json["temperatur"] as String,
          instructions: List.from(json["instructions"] as List),
          notes: json["notes"] as String,
          isFavorite: json["isFavorite"] as bool,
        );
      }
    
      Map toJson() {
        return {
          "id": id,
          "meatType": meatType,
          "meatTypeImg": meatTypeImg,
          "meatCut": meatCut,
          "duration": duration,
          "temperatur": temperatur,
          "instructions": instructions,
          "notes": notes,
          "isFavorite": isFavorite,
        };
      }
    }
    

    This is the part to store and retrieve in SP:

      List<SvItem> customRecipes = [];
      String customRecipeString = "";
      XFile? image;
      SvItem? item;
    
      @override
      void initState() {
        getStringState().then((value) {
          setState(() {
            List customRecipesJsonList = jsonDecode(value);
            for (var item in customRecipesJsonList) {
              SvItem customItem = SvItem.fromJson(jsonDecode(item));
              var contain =
                  customRecipes.where((element) => element.id == customItem.id);
              if (contain.isEmpty) {
                customRecipes.add(customItem);
              }
            }
          });
        });
    
        super.initState();
      }
    
      Future<Future<bool>> saveStringState(String string) async {
        SharedPreferences prefs = await SharedPreferences.getInstance();
        prefs.setString("customRecipes", string);
        return prefs.setString("customRecipes", string);
      }
    
      Future<String> getStringState() async {
        SharedPreferences prefs = await SharedPreferences.getInstance();
        String? customRecipeString = prefs.getString("customRecipes");
        return customRecipeString as String;
      }
    
      getStringValues() async {
        customRecipeString = await getStringState();
        setState(() {});
      }
    

    And this let's me save to SP and also decode it again:

                      customRecipes.add(item);
                      List customRecipesJson = [];
                      for (SvItem item in customRecipes) {
                        String jsonCustomItem = jsonEncode(item);
                        customRecipesJson.add(jsonCustomItem);
                      }
                      String customRecipesJsonString =
                          jsonEncode(customRecipesJson);
                      saveStringState(customRecipesJsonString);
                      print(customRecipesJsonString);
    
                      List customRecipesJsonList =
                          jsonDecode(customRecipesJsonString);
                      for (var item in customRecipesJsonList) {
                        SvItem customItem =
                            SvItem.fromJson(jsonDecode(item));
                        var contain = customRecipes.where(
                            (element) => element.id == customItem.id);
                        if (contain.isEmpty) {
                          customRecipes.add(customItem);
                        }
                      }
    

  2. when you use jsonDecode(recipeData!) it will get a Map not a List.

    try convert the code :

    List<SvItem> customRecipes =
        SvItem.fromJson(jsonDecode(recipeData!)) as List<SvItem>;
    

    into this :

    Map<String, dynamic> customRecipes =
        SvItem.fromJson(jsonDecode(recipeData!));
    

    also why did you use jsonEncode not the method toJson from your model class?

    Login or Signup to reply.
  3. You said that you pass a List<SvItem> to the function.
    So you can loop over the list and turn each item into json.
    Then you add the json objects to another list and encode it.

    Try this:

    Future saveCustomRecipes(List<SvItem> items) async {
      SharedPreferences prefs = await SharedPreferences.getInstance();
      sv_items = [];
      for(SvItem item in items)
      {
         sv_items.add(item.toJson());
      }
      await prefs.setString("customRecipesList", jsonEncode(sv_items));
    }
    

    and

    Future getCustomRecipesState() async {
        final prefs = await SharedPreferences.getInstance();
        var recipeData = prefs.getString("customRecipesList");
        List<Map<String, dynamic>> items = jsonDecode(recipeData!) as List<Map<String, dynamic>>;
        List<SvItem> customRecipes = [];
        for(Map<String, dynamic> item in items)
        {
           customRecipes.add(SvItem.fromJson(item));
        }
        print(customRecipes);
        return customRecipes;
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search