skip to Main Content

I have fetched the details of the planet i.e. (NOM) No. of moons, Gravity and Density from an API.
And i have stored these details in an array PlanetInfo. And i want to display it using text widget like Text("${PlanetInfo[1]}", style: TextStyle(color: Colors.white)). but it is giving me an erro: RangeError (index): Invalid value: Valid value range is empty: 1

import 'dart:convert';
import 'package:http/http.dart' as http;
import 'package:flutter/material.dart';
import 'package:xperience/Models/planets.dart';

class PlanetDescNoMGD extends StatelessWidget {
  final Planet planeteee;
  List PlanetInfo = [];
  getPlanetData() async {
    var url =
        "https://api.le-systeme-solaire.net/rest/bodies/${planeteee.planetApi}";
    final uri = Uri.parse(url);
    final response = await http.get(uri);
    final body = response.body;
    final jsondata = jsonDecode(body);

    PlanetInfo.add(jsondata["moons"].length);
    PlanetInfo.add(jsondata["gravity"]);
    PlanetInfo.add(jsondata["density"]);
  }

  PlanetDescNoMGD({Key? key, required this.planeteee}) : super(key: key);
  @override
  void initState() {
    this.getPlanetData();
  }

  @override
  Widget build(BuildContext context) {
    return Row(
      mainAxisAlignment: MainAxisAlignment.spaceAround,
      children: <Widget>[
        Column(
          crossAxisAlignment: CrossAxisAlignment.center,
          children: <Widget>[
            const Text(
              "No. of moons",
              style:
                  TextStyle(color: Colors.white, fontWeight: FontWeight.w700),
            ),
            const SizedBox(
              height: 12,
            ),
            Text("${PlanetInfo[1]}", style: TextStyle(color: Colors.white))
          ],
        ),
        Column(
          crossAxisAlignment: CrossAxisAlignment.center,
          children: <Widget>[
            const Text(
              "Gravity",
              style:
                  TextStyle(color: Colors.white, fontWeight: FontWeight.w600),
            ),
            const SizedBox(
              height: 12,
            ),
            Text("${PlanetInfo[1]}" + " m/s²",
                style: TextStyle(color: Colors.white))
            //Text(${num} + " m/s²", style: TextStyle(color: Colors.white))
          ],
        ),
        Column(
          crossAxisAlignment: CrossAxisAlignment.center,
          children: <Widget>[
            const Text(
              "Density",
              style:
                  TextStyle(color: Colors.white, fontWeight: FontWeight.w600),
            ),
            const SizedBox(
              height: 12,
            ),
            Text("${PlanetInfo[2]}" + " g/cm3",
                style: TextStyle(color: Colors.white))
          ],
        ),
      ],
    );
  }
}

I need a solution.

2

Answers


    1. You do not know how to work with async functions. Please learn it.
      You are making async request to API and directly trying to use respond from API. It is not possible. What is happening is your List PlanetInfo is empty when build is called. so you are getting error.

    2. Stateless widgets does not have initState! I see you are trying to override initState that does not exist.

    3. You need stateful widget to use setState.

    4. Here is, with minimal change working version of your code. You need to use setState after data is loaded and change isLoaded = true.

    Here is solution:

    import 'dart:convert';
    import 'package:http/http.dart' as http;
    import 'package:flutter/material.dart';
    import 'package:xperience/Models/planets.dart';
    
    class PlanetDescNoMGD extends StatefulWidget {
      PlanetDescNoMGD({Key? key, required this.planeteee}) : super(key: key);
    
      final Planet planeteee;
    
      @override
      State<PlanetDescNoMGD> createState() => _PlanetDescNoMGDState();
    }
    
    class _PlanetDescNoMGDState extends State<PlanetDescNoMGD> {
      List PlanetInfo = [];
    
      bool isLoaded = false;
    
      getPlanetData() async {
        var url =
            "https://api.le-systeme-solaire.net/rest/bodies/${widget.planeteee.planetApi}";
        final uri = Uri.parse(url);
        final response = await http.get(uri);
        final body = response.body;
        final jsondata = jsonDecode(body);
    
        PlanetInfo.add(jsondata["moons"].length);
        PlanetInfo.add(jsondata["gravity"]);
        PlanetInfo.add(jsondata["density"]);
        setState(() {
          isLoaded = true;
        });
      }
    
      @override
      void initState() {
        super.initState();
        getPlanetData();
      }
    
      @override
      Widget build(BuildContext context) {
        return !isLoaded
            ? const Center(child: CircularProgressIndicator())
            : Row(
                mainAxisAlignment: MainAxisAlignment.spaceAround,
                children: <Widget>[
                  Column(
                    crossAxisAlignment: CrossAxisAlignment.center,
                    children: <Widget>[
                      const Text(
                        "No. of moons",
                        style: TextStyle(
                            color: Colors.white, fontWeight: FontWeight.w700),
                      ),
                      const SizedBox(
                        height: 12,
                      ),
                      Text("${PlanetInfo[1]}",
                          style: TextStyle(color: Colors.white))
                    ],
                  ),
                  Column(
                    crossAxisAlignment: CrossAxisAlignment.center,
                    children: <Widget>[
                      const Text(
                        "Gravity",
                        style: TextStyle(
                            color: Colors.white, fontWeight: FontWeight.w600),
                      ),
                      const SizedBox(
                        height: 12,
                      ),
                      Text("${PlanetInfo[1]}" + " m/s²",
                          style: TextStyle(color: Colors.white))
                      //Text(${num} + " m/s²", style: TextStyle(color: Colors.white))
                    ],
                  ),
                  Column(
                    crossAxisAlignment: CrossAxisAlignment.center,
                    children: <Widget>[
                      const Text(
                        "Density",
                        style: TextStyle(
                            color: Colors.white, fontWeight: FontWeight.w600),
                      ),
                      const SizedBox(
                        height: 12,
                      ),
                      Text("${PlanetInfo[2]}" + " g/cm3",
                          style: TextStyle(color: Colors.white))
                    ],
                  ),
                ],
              );
      }
    }
    
    Login or Signup to reply.
  1. You have got 2 things to fix there.

    1. Class.
      Do not use PlanetInfo as a list of ints.
      Make full use of defining a class: encapsulating data and improving readability.

    Define the class as follows

    PlanetInfo{
    int noOfMoons;
    double gravity;
    double density;
    PlanetInfo({
     required this.noOfMoons,
     required this.gravity,
     required this.density,
     });
    }
    

    Declare a member in state.

    List PlanetInfo = [];//remove this
    late final PlanetInfo myPlanet;// use this
    
    

    Now create an object in your fetch call and assign it to state member.

     final jsondata = jsonDecode(body);
    
        PlanetInfo tempPlanet=PlanetInfo(
                   noOfMoons: jsondata["moons"].length,
                   gravity: jsondata["gravity"],
                   density: jsondata["density"],
    );
    myPlanet=x; // use setState() if required
    
    

    and display in widgets using attributes.

    //rest of code
    
        Text("${planetInfo.noOfMoons}",
    
     //rest of code
    
         Text("${planetInfo.gravity}}" + " m/s²",'
    
     //rest of code  
                
         Text("${planetInfo.density}" + " g/cm3",
    
     //rest of code
    
    1. Displaying API data.

    You can either use FutureBuilder to wait on building UI until api call is done, or do as @hiloliddin suggested (using isLoaded member and building ui based on its value).

    In your current implementation you were getting the error because UI was built before api call finished and the list PlanetInfo was empty.

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