I have a ListView.builder
widget wrapped inside a RefreshIndicator
and then a FutureBuilder
. Refreshing does not update my list, I have to close the app and open it again but the refresh code does the same as my FutureBuilder
.
Please see my code below, when I read it I expect the widget tree to definitely update.
@override
void initState() {
super.initState();
taskListFuture= TaskService().getTasks();
}
@override
Widget build(BuildContext context) {
return Consumer<TaskData>(builder: (context, taskData, child) {
return FutureBuilder(
future: taskListFuture,
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
taskData.tasks = (snapshot.data as ApiResponseModel).responseBody;
return RefreshIndicator(
onRefresh: () async {
var responseModel = await TaskService().getTasks();
setState(() {
taskData.tasks = responseModel.responseBody;
});
},
child: ListView.builder(
...
...
Let me know if more code is required, thanks in advance!
Points
- I am using a StatefulWidget
- Task data is a class that extends ChangeNotifier
- When I debug the refresh I can see the new data in the list, but the UI does not update
getTasks()
Future<ApiResponseModel> getTasks() async {
try {
var _sharedPreferences = await SharedPreferences.getInstance();
var userId = _sharedPreferences.getString(PreferencesModel.userId);
var response = await http.get(
Uri.parse("$apiBaseUrl/$_controllerRoute?userId=$userId"),
headers: await authorizeHttpRequest(),
);
var jsonTaskDtos = jsonDecode(response.body);
var taskDtos= List<TaskDto>.from(
jsonTaskDtos.map((jsonTaskDto) => TaskDto.fromJson(jsonTaskDto)));
return ApiResponseModel(
responseBody: taskDtos,
isSuccessStatusCode: isSuccessStatusCode(response.statusCode));
} catch (e) {
return null;
}
}
CodePudding user response:
The issue here seems to be that you are updating a property that is not part of your StatefulWidget state.
setState(() {
taskData.tasks = responseModel.responseBody;
});
That sets a property part of TaskData
.
My suggestion is to only use the Consumer
and refactor TaskService
so it controls TaskData
or similar. Something like:
Consumer<TaskService>(builder: (context, service, child) {
return RefreshIndicator(
onRefresh: () {
service.getTasks();
},
child: ListView()); //Uses service.data to build the list items
}
and make sure to call notifyListeners()
in the service.getTasks() method to make the Consumer
rebuild
CodePudding user response:
I think (someone will correct me if I'm wrong) the problem is that you are using the FutureBuilder
, once it's built, you need to refresh to whole widget for the FutureBuilder to listen to changes. I can suggest a StreamBuilder
that listens to any changes provided from the data model/api/any kind of stream of data. Or better yet, you can use some sort of state management like Provider
and use Consumer
from the Provider package that notifies the widget of any changes that may occurred.