I'm trying to make dynamically created checkboxes with a ListView. If I restart the simulator and go to my search page, the checkboxes aren't there. If I "hot reload" the simulator (ctrl + S) the checkboxes show up. If I go back to the menu and come back to the search page, the checkboxes are gone. If I click on "search" to search for the recipes in my database, the checkboxes reappear. I don't know what's going on here.

Here is my categories map:

  Map<String, bool> categoryMap = {};
  var checkedCategories = [];

  void findCategories() async {

    int responseCode = await categories();
    print(responseCode);

    if(responseCode == 200){
      newCategories = categoriesList;

      for(int i = 0; i < newCategories.length; i++){
        categoryMap.putIfAbsent(newCategories[i]['name'].toString(), () => false);
      }

      print("new categories of length ${newCategories.length} are: " + newCategories[1]['name'].toString());
      print("categoryMap is: " + categoryMap.toString());
    } else {
      print("Error: unauthorized");
    }
  }

  getCheckedCategories(){

    categoryMap.forEach((key, value) {
      if(value == true)
      {
        checkedCategories.add(key);
      }
    });

    // Printing all selected items on Terminal screen.
    print(checkedCategories);
    print(categoryMap.keys);
    // Here you will get all your selected Checkbox items.

    // Clear array after use.
    checkedCategories.clear();
  }

  @override
  void initState() {
    super.initState();
    findCategories();
    print('hi there');
  }

And here is where I am trying to show the checkboxes:

child: Column(
    children: [
        SizedBox(height: 40.0,),
        new ListView(
            scrollDirection: Axis.vertical,
            shrinkWrap: true,
            children: categoryMap.keys.map((String key) {
              //print("here is a new checkbox!");
              return new CheckboxListTile(
                title: new Text(key),
                value: categoryMap[key],
                activeColor: Colors.pink,
                checkColor: Colors.white,
                onChanged: (bool value) {
                  setState(() {
                    categoryMap[key] = value;
                  });
                },
              );
            }).toList(),
        ),
      isLoading ? Center(
        child: CircularProgressIndicator(),
      ) : new RaisedButton(
        child: Text('Search'),
        color: Colors.orange[600],
        textColor: Colors.white,
        onPressed: () async {
          setState(() {
            isLoading = true; //Data is loading
          });

          /*int response_code = await categories();
          print(response_code);*/
          clearResults();

          await getRecipe(searchController.text);
          Navigator.push(context, MaterialPageRoute(builder: (context)=>RecipeResultsPage()));

          /*if(response_code == 200){
            await getRecipe(searchController.text);
            Navigator.push(context, MaterialPageRoute(builder: (context)=>RecipeResultsPage()));
          } else {
            print("Error: unauthorized");
          }*/
        },
      ),

Here is a demonstration of the bug (notice how the checkboxes disappear if I go back to the menu and come back to the search page):

Also notice how the checkboxes appear if I click on the search button


Solution 1: Martin

Try wrapping the code where you update categoryMap in a setState like this:

setState(() {
      for(int i = 0; i < newCategories.length; i++){
        categoryMap.putIfAbsent(newCategories[i]['name'].toString(), () => false);
      }
});