Flutter Error : Unhandled Exception: RangeError (index): Invalid value: Valid value range is empty: 0

Flutter Error : Unhandled Exception: RangeError (index): Invalid value: Valid value range is empty: 0

Problem Description:

I am trying to fetch data from an API, and although data is fetched for a hardcoded request, I am unable to get it dynamically.

It gives the following error:

E/flutter (11813): [ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: RangeError (index): Invalid value: Valid value range is empty: 0
E/flutter (11813): #0      List.[] (dart:core-patch/growable_array.dart:264:36)
E/flutter (11813): #1      new Album.fromJson (package:todoapp/models/apihandler.dart:34:32)
E/flutter (11813): #2      fetchAlbum (package:todoapp/models/apihandler.dart:13:18)
E/flutter (11813): <asynchronous suspension>

My home screen code is :

import 'package:flutter/material.dart';
import 'package:todoapp/constants.dart';
import 'package:todoapp/models/apihandler.dart';

class NutrientFact extends StatefulWidget {
  @override
  State<NutrientFact> createState() => _NutrientFactState();
}

class _NutrientFactState extends State<NutrientFact> {
  @override
  late String inputdata;

  // late Future<Album> futureAlbum;
  late double proteins = 0;

  late double carbs = 0;

  late double fibers = 0;

  late double fats = 0;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: const Center(
              child: Text(
            'SelfTime',
            style: TextStyle(fontWeight: FontWeight.bold),
          )),
        ),
        body: Column(
          crossAxisAlignment: CrossAxisAlignment.stretch,
          mainAxisAlignment: MainAxisAlignment.spaceBetween,
          children: [
            Expanded(
                child: TextField(
              textAlign: TextAlign.center,
              onChanged: (value) {
                inputdata = value;
              },
            )),
            FactEntry("Protein", proteins.toString()),
            FactEntry("Carbohydrates", carbs.toString()),
            FactEntry("Fats", fats.toString()),
            FactEntry("Fiber", fibers.toString()),
            GestureDetector(
              child: Container(
                alignment: Alignment.center,
                margin: EdgeInsets.only(top: 10),
                color: kBottomButtonColor,
                width: double.infinity,
                height: kBottomButtonHeight,
                child: Text(
                  "SEARCH",
                  style: TextStyle(fontWeight: FontWeight.w600, fontSize: 30),
                ),
              ),
              onTap: () {
                setState(() {
                  FutureBuilder<Album>(
                    future: fetchAlbum(ing: inputdata),
                    builder: (context, snapshot) {
                      if (snapshot.hasData) {
                        proteins = snapshot.data!.protein;
                        carbs = snapshot.data!.carb;
                        fats = snapshot.data!.fat;
                        fibers = snapshot.data!.fiber;
                        print(proteins);
                      } else if (snapshot.hasError) {
                        return Text('-----${snapshot.error}');
                      }
                      return CircularProgressIndicator();
                    },
                  );
                });
              },
            ),
          ],
        ));
  }
}

class FactEntry extends StatelessWidget {
  FactEntry(this.label, this.data);
  late String label;
  late String data;

  @override
  Widget build(BuildContext context) {
    return Expanded(
      child: Padding(
        padding: EdgeInsets.symmetric(horizontal: 15, vertical: 20),
        child: Container(
          decoration: kContainerDecoration,
          child: Row(
            crossAxisAlignment: CrossAxisAlignment.stretch,
            mainAxisAlignment: MainAxisAlignment.spaceEvenly,
            children: [
              Center(
                  child: Text(
                label,
                style: TextStyle(fontSize: 20),
              )),
              Center(child: Text(data, style: TextStyle(fontSize: 20)))
            ],
          ),
        ),
      ),
    );
  }
}

And API handler is:

import 'dart:convert';
import 'package:http/http.dart' as http;

Future<Album> fetchAlbum({String ing = 'chicken'}) async {
  final response = await http.get(
    Uri.parse(
        "https://api.edamam.com//api//food-database//v2//parser?app_id=$api_id&app_key=$api_key&ingr=ing&nutrition-type=cooking"),
  );

  if (response.statusCode == 200) {
    return Album.fromJson(jsonDecode(response.body));
  } else {
    throw Exception('Failed to load album');
  }
}

class Album {
  final double carb;
  final double protein;
  final double fat;
  final double fiber;

  const Album({
    required this.carb,
    required this.protein,
    required this.fat,
    required this.fiber,
  });

  factory Album.fromJson(Map<String, dynamic> json) {
    return Album(
        protein: json["parsed"][0]["food"]["nutrients"]["PROCNT"],
        fat: json["parsed"][0]["food"]["nutrients"]["FAT"],
        fiber: json["parsed"][0]["food"]["nutrients"]["CHOCDF"],
        carb: json["parsed"][0]["food"]["nutrients"]["FIBTG"]);
  }
}

`

Solution – 1

Its seems your json["parsed"] is empty, but you try to call first item in that, to avoid this happen you can parse your list dynamically like this:

factory Album.fromJson(Map<String, dynamic> json) {
    return Album(
        protein: json["food"]["nutrients"]["PROCNT"],
        fat: json["food"]["nutrients"]["FAT"],
        fiber: json["food"]["nutrients"]["CHOCDF"],
        carb: json["food"]["nutrients"]["FIBTG"]);
  }

then change fetchAlbum to this:

Future<List<Album>> fetchAlbum({String ing = 'chicken'}) async {
  final response = await http.get(
    Uri.parse(
        "https://api.edamam.com//api//food-database//v2//parser?app_id=$api_id&app_key=$api_key&ingr=ing&nutrition-type=cooking"),
  );

  if (response.statusCode == 200) {
    
    return (jsonDecode(response.body)["parsed"] as List).map((e) => Album.fromJson(e)).toList();
  } else {
    throw Exception('Failed to load album');
  }
}

also you need to change your FutureBuilder to this:

FutureBuilder<List<Album>>(
    future: fetchAlbum(ing: inputdata),
    builder: (context, snapshot) {
      switch (snapshot.connectionState) {
        case ConnectionState.waiting:
          return CircularProgressIndicator();
        default:
          if (snapshot.hasError) {
            return Text('Error: ${snapshot.error}');
          } else {
            List<Album> data = snapshot.data ?? [];

            return ListView.builder(
              itemBuilder: (context, index) {
                proteins = data[index].protein;
                carbs = data[index].carb;
                fats = data[index].fat;
                fibers = data[index].fiber;

                print(proteins);
                return Column(children: [
                  Text('${data[index].protein ?? ""}'),
                ]);
              },
              itemCount: data.length,
            );
          }
      }
    },
  ),
Rate this post
We use cookies in order to give you the best possible experience on our website. By continuing to use this site, you agree to our use of cookies.
Accept
Reject