The argument type 'Future<List<User>>' can't be assigned to the parameter type 'Future<void> Function()' in onRefresh when using RefreshIndicator

Issue

I am having a Future that is fetching and populating users below

Future<List<User>> _fetchUsersListUsingLoop() async {
    try {
      
      var response = await http.get(
          Uri.parse(
              "https://api.json-generator.com/templates/Eh5AlPjYVv6C/data"),
          headers: {
            "Content-Type": "application/json",
            "Authorization": "Bearer tltsp6dmnbif01jy9xfo9ssn4620u89xhuwcm5t3",
          });


      List<User> usersList = [];

      for (var u in json.decode(response.body)) {
        User user = User(u["email"], u["about"], u["name"], u["picture"],
            u["index"], u["imageFetchType"]);

        usersList.add(user);
      }

      return usersList;
    } catch (e) {
      log("FetchUsersListUsingLoopException $e");

      rethrow;
    }
  }

And below is how i am using future in FutureBuilder to call _fetchUsersListUsingLoop() and then use ListView.builder inside RefreshIndicator to show users in the list

body: SizedBox(
        child: FutureBuilder(
            future: _fetchUsersListUsingLoop(),
            builder: (BuildContext context, AsyncSnapshot asyncSnapshot) {
              if (asyncSnapshot.data == null) {
                return const Center(child: CircularProgressIndicator());
              } else {
                return RefreshIndicator(
                  // background color
                    backgroundColor: Colors.white,
                    // refresh circular progress indicator color
                    color: Colors.green,
                    onRefresh: _fetchUsersListUsingLoop(),
                    child: ListView.builder(
                      itemCount: asyncSnapshot.data.length,
                      itemBuilder: (BuildContext context, int index) {
                        return ListTile(
                          contentPadding: const EdgeInsets.all(10),
                          leading: CircleAvatar(
                            backgroundImage:
                                NetworkImage(asyncSnapshot.data[index].picture),
                          ),
                          title: Text(asyncSnapshot.data[index].name),
                          subtitle: Text(
                              "${asyncSnapshot.data[index].email} \nUsing NetworkImage with backgroundImage"),
                        );
                      },
                    ));
              }
            }),
      ),

I am getting The argument type 'Future<List<User>>' can't be assigned to the parameter type 'Future<void> Function()'. error in this line onRefresh: _fetchUsersListUsingLoop(), How can i be able to call _fetchUsersListUsingLoop() again when i swipe down to refresh

Solution

Instead of calling _fetchUsersListUsingLoop you should use setState to cause a rebuild so that FutureBuilder fetches the data again.

onRefresh: () => setState(() {})

That being said it’s best to store your future in initState and update this future when needed by calling setState. This is from documentation:

The future must have been obtained earlier, e.g. during State.initState, State.didUpdateWidget, or State.didChangeDependencies. It must not be created during the State.build or StatelessWidget.build method call when constructing the FutureBuilder. If the future is created at the same time as the FutureBuilder, then every time the FutureBuilder’s parent is rebuilt, the asynchronous task will be restarted.

Future<List<User>>? _usersFuture;

@override
  void initState() {
    super.initState();
    _usersFuture = _fetchUsersListUsingLoop();
}

Then:

onRefresh: () {
    setState(() {
      _usersFuture = _fetchUsersListUsingLoop();
    });
  }

Answered By – Ramin

Answer Checked By – Senaida (FlutterFixes Volunteer)

Leave a Reply

Your email address will not be published. Required fields are marked *