skip to Main Content

I’m busy coding a page in my flutter app where I would like it to display a list view from a json file but it keeps giving error [ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: Unable to load asset: "lib/data/json/foods/foods.json".
The asset does not exist or has empty data.

this is my dart json decoder

class Food {
  String name;
  double caloriesPer100g;
  double fatPer100g;
  double ofWhichSaturates;
  double carbohydratesPer100g;
  double ofWhichSugars;
  double proteinPer100g;
  double SodiumPer100g;
  double ServingSizeGrams;

  Food(
    this.name,
    this.caloriesPer100g,
    this.fatPer100g,
    this.ofWhichSaturates,
    this.carbohydratesPer100g,
    this.ofWhichSugars,
    this.proteinPer100g,
    this.SodiumPer100g,
    this.ServingSizeGrams,
  );

  Food.fromJson(Map<String, dynamic> json)
      : name = json['name'],
        caloriesPer100g = json["caloriesPer100g"] ?? 0,
        fatPer100g = json["fatPer100g"] ?? 0,
        ofWhichSaturates = json["ofWhichSaturates"] ?? 0,
        carbohydratesPer100g = json["carbohydratesPer100g"] ?? 0,
        ofWhichSugars = json["ofWhichSugars"] ?? 0,
        proteinPer100g = json["proteinPer100g"] ?? 0,
        SodiumPer100g = json["SodiumPer100g"] ?? 0,
        ServingSizeGrams = json["ServingSizeGrams"] ?? 0;
}

this is the first 3 elements of the json file

{
            "name": "Chobani Greek Yogurt",
            "caloriesPer100g": 59,
            "fatPer100g": 0,
            "ofWhichSaturates": 0,
            "carbohydratesPer100g": 4,
            "ofWhichSugars": 4,
            "proteinPer100g": 10,
            "SodiumPer100g": 0.04,
            "ServingSizeGrams": 150 
        },
        {
            "name": "Oikos Triple Zero Greek Yogurt",
            "caloriesPer100g": 83,
            "fatPer100g": 0,
            "ofWhichSaturates": 0,
            "carbohydratesPer100g": 6,
            "ofWhichSugars": 6,
            "proteinPer100g": 15,
            "SodiumPer100g": 0.06,
            "ServingSizeGrams": 150 
        },
        {
            "name": "Fage Total 0% Greek Yogurt",
            "caloriesPer100g": 50,
            "fatPer100g": 0,
            "ofWhichSaturates": 0,
            "carbohydratesPer100g": 4,
            "ofWhichSugars": 4,
            "proteinPer100g": 10,
            "SodiumPer100g": 0.05,
            "ServingSizeGrams": 150 
        },

and this is the file where i plan to show the list of json foods

import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:sg_training/data/json/foods/foods.dart';

class AddFood extends StatefulWidget {
  @override
  _AddFoodState createState() => _AddFoodState();
}

class _AddFoodState extends State<AddFood> {
  List<Food> _foods = []; // Move _foods list to _AddFoodState

  @override
  void initState() {
    super.initState();
    // Call fetchFoods method when the widget is initialized
    fetchFoods().then((foods) {
      setState(() {
        _foods = foods;
      });
    });
  }

  Future<List<Food>> fetchFoods() async {
    // Load JSON data from the assets
    String jsonString = await DefaultAssetBundle.of(context)
        .loadString('lib/data/json/foods/foods.json');

    // Decode JSON
    var foodsJson = json.decode(jsonString);

    // Create a list to store parsed Food objects
    List<Food> foods = [];

    // Iterate over the JSON array and convert each item to Food object
    for (var foodJson in foodsJson) {
      foods.add(Food.fromJson(foodJson));
      print(foods);
    }

    return foods;
  }

  @override
  Widget build(BuildContext context) {
    fetchFoods().then((value) {
      _foods.addAll(value);
    });
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          centerTitle: true,
          leading: BackButton(
            onPressed: () {
              Navigator.pop(context);
            },
          ),
          title: Text("SG training"),
          backgroundColor: Colors.blueGrey,
        ),
        body: ListView.builder(
          itemBuilder: (context, index) {
            return Card(
              child: Padding(
                child: Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    Text(
                      _foods[index].name,
                      style: TextStyle(
                          fontSize: 15.0, fontWeight: FontWeight.bold),
                    ),
                    Text(
                      _foods[index].caloriesPer100g.toString(),
                      style: TextStyle(color: Colors.grey.shade700),
                    )
                  ],
                ),
                padding: EdgeInsets.all(15),
              ),
            );
          },
          itemCount: _foods.length, // Use _foods.length as itemCount
        ),
      ),
    );
  }
}

ive tried two different ways of decoding the json but neither of them work

it should display a list on the screen but it keeps giving an error

i dont know if its the json file the decoder or where i access the decoder but i would be a great help if anyone know how to fix it

2

Answers


  1. You can use a FutureBuilder widget to handle asynchronous operations like fetching data from a JSON file. Here’s how you can refactor your AddFood widget to use FutureBuilder

        class AddFood extends StatelessWidget {
        Future<List<Food>> fetchFoods(BuildContext context) async {
            // Load JSON data from the assets
            String jsonString = await DefaultAssetBundle.of(context)
                .loadString('lib/data/json/foods/foods.json');
    
            // Decode JSON
            var foodsJson = json.decode(jsonString);
    
            // Create a list to store parsed Food objects
            List<Food> foods = [];
    
            // Iterate over the JSON array and convert each item to Food object
            for (var foodJson in foodsJson) {
              foods.add(Food.fromJson(foodJson));
            }
    
            return foods;
          }
          @override
          Widget build(BuildContext context) {
            return MaterialApp(
              home: Scaffold(
                appBar: AppBar(
                  centerTitle: true,
                  leading: BackButton(
                    onPressed: () {
                      Navigator.pop(context);
                    },
                  ),
                  title: Text("SG training"),
                  backgroundColor: Colors.blueGrey,
                ),
                body: FutureBuilder<List<Food>>(
                  future: fetchFoods(context),
                  builder: (context, snapshot) {
                    if (snapshot.connectionState == ConnectionState.waiting) {
                      return Center(
                        child: CircularProgressIndicator(),
                      );
                    } else if (snapshot.hasError) {
                      return Center(
                        child: Text('Error: ${snapshot.error}'),
                      );
                    } else {
                      List<Food> foods = snapshot.data;
                      return ListView.builder(
                        itemBuilder: (context, index) {
                          return Card(
                            child: Padding(
                              child: Column(
                                crossAxisAlignment: CrossAxisAlignment.start,
                                children: [
                                  Text(
                                    foods[index].name,
                                    style: TextStyle(
                                      fontSize: 15.0,
                                      fontWeight: FontWeight.bold,
                                    ),
                                  ),
                                  Text(
                                    foods[index].caloriesPer100g.toString(),
                                    style: TextStyle(color: Colors.grey.shade700),
                                  )
                                ],
                              ),
                              padding: EdgeInsets.all(15),
                            ),
                          );
                        },
                        itemCount: foods.length,
                      );
                    }
                  },
                ),
              ),
            );
          }
        }
    

    In this version, the fetchFoods function is moved out of the stateful widget and into the AddFood class. The AddFood widget itself is now a stateless widget. The fetchFoods function now takes a BuildContext as an argument to access the context needed for loading the asset.

    The UI is built using a FutureBuilder, which handles the asynchronous fetching of data. It displays a loading spinner while waiting for the data, shows an error message if an error occurs, and displays the list of foods once the data is loaded successfully.

    Also If you are Familiar with JsonSerializable package you can rewrite the class in such a way

    import 'package:json_annotation/json_annotation.dart';
    
    part 'food.g.dart';
    
    @JsonSerializable()
    class Food {
      String name;
      double caloriesPer100g;
      double fatPer100g;
      double ofWhichSaturates;
      double carbohydratesPer100g;
      double ofWhichSugars;
      double proteinPer100g;
      double SodiumPer100g;
      double ServingSizeGrams;
    
      Food(
        this.name,
        this.caloriesPer100g,
        this.fatPer100g,
        this.ofWhichSaturates,
        this.carbohydratesPer100g,
        this.ofWhichSugars,
        this.proteinPer100g,
        this.SodiumPer100g,
        this.ServingSizeGrams,
      );
    
      factory Food.fromJson(Map<String, dynamic> json) => _$FoodFromJson(json);
    
      Map<String, dynamic> toJson() => _$FoodToJson(this);
    }
    
    

    Make sure you have json_annotation and build_runner dependencies added to your pubspec.yaml file, and run the build command to generate the serialization/deserialization code:

    dependencies:
      flutter:
        sdk: flutter
      json_annotation: // any latest version
    
    dev_dependencies:
      flutter_test:
        sdk: flutter
      build_runner: // any latest version
      json_serializable: // any latest version
    
    flutter:
      assets:
        - data/local/
    

    then run:

    flutter pub run build_runner build
    
    Login or Signup to reply.
  2. This is because Flutter cannot detect the file path
    You need to specify the path in the pubspac.yaml file

    assets:
      - data/local/food.json
    

    It is also better to put your json in an array because the structure is the same but the count is different

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search