I have dynamically created a list view by getting data from an API and putting it into a list of objects, however, when I open the screen, which is opened by pressing a button on another screen, the only way to get the ListView to show on screen is to do a hot refresh. I've tried setting the state in the init_state function but it doesn't seem to be working.

Thanks for any help :)

class _PlanetListState extends State<PlanetList> {

List<Planet> planets = [];
String urlWeb = 'https://swapi.dev/api/planets/';

Future getData(String url) async {

    var response = await http.get(url);
    if (response.statusCode == 200) {
        var data = json.decode(response.body);

    Planet obj = Planet(
      name: data['name'],
      rotationPeriod: data['rotation_period'],
      orbitalPeriod: data['orbital_period'],
      diameter: data['diameter'],
      climate: data['climate'],
      gravity: data['gravity'],
      terrain: data['terrain'],
      population: data['population']
      );
      planets.add(obj);

      print(planets);
    }
}

@override
  void initState() {
    for (var i=0;i<62;i++){
      getData('$urlWeb$i/');
    }
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("Planets"),
        backgroundColor: Colors.amber[800],
      ),
      body: Container(
        color: Colors.black,
        child: ListView.builder(
          itemCount: planets.length,
          itemBuilder: (BuildContext context, int index){
            return Card(
              color: Colors.amber[600],
              margin:EdgeInsets.all(8),
              child: ListTile(
                leading: CircleAvatar(
                  backgroundColor: getColor(planets[index].climate),
                  backgroundImage: AssetImage('assets/planet.png'),
                ),
                contentPadding: EdgeInsets.all(5),
                title: Text('$index: ${planets[index].name}'),
                subtitle:Text(planets[index].climate),
             ),
           );
          },
        ),
      ),
    );
  }
}


Solution 1: Abbas.M

What's happening is that your screen is loading before your data are added to the list, this is because your getData function is async. So when your screen first loads the list is empty, and as you may know in order to show changes on the screen you must do a setState(), this is why when you hot refresh the changes appear.

Now you have multiple options here, first you can take a look at the FutureBuilder, this is a widget that would build twice, once before your Future is resolved and once afterwards, meaning it "auto refreshes". In this case your list of data would become the Future type and your ListView would be wrapped with a FutureBuilder so it's built after the data are ready.

Another option would be to do a setState() every time you add an item to the List of objects you have.