Home > front end >  Using ListView with async items without knowing itemCount beforehand
Using ListView with async items without knowing itemCount beforehand

Time:10-13

I want to use Flutter’s ListView to display a list of items, and the data of the items are obtained from a RESTful API with pagination support. E.g.

GET /transactions?page=1&limit=10
{
  "transactions": [ ... ]
  "pagination": {
     "total": 100
  }
}

I know I can use ListView.builder(), and let the itemBuilder callback argument returns a widget wrapped in FutureBuilder.

However, ListView.builder() also has a itemCount argument. I don’t know the total count of items before fetching the first page. Without the itemCount argument, the itemBuilder may be called with index exceeding the total number of items.

One way that comes to my mind is to wrap the ListView in another FutureBuilder and asynchronously call the API to get the total count. However, the total count may change over time. For example, the total count can be 100 initially. But when the user scrolls to the end, some items are removed, and the total count becomes 90. When it happens, it’s still possible that itemBuilder is called with index out of bound.

What should I do to deal with this situation?

CodePudding user response:

If I understand you well, and from what I can see in the response. you want to do a pagination thing. use infinite_scroll_pagination

CodePudding user response:

This shouldn't be an issue. You should call ListView.builder() only when you already have the API items properly returned. And if that's the case, you can tell the length of the items (after they have successfully returned), and use this length as the itemCount of ListView.builder().

Any other solution you use (asides ListView.builder()) will still require the API to return the data successfully before rendering the UI (based on the returned data).

If you understand the above, then your problem should be solved.


But if it still doesn't solve it, use ListView with children instead of the .builder method.

After the API has returned the items, call .map method on the returned List/Iterable (from the API). This method should return the widgets that your .builder() would have returned. You are calling this .map method against children property of ListView. Something like:

ListView(
  // where items is from the API
  children: items.map((i) => Text(i)).toList(), 
)

You can choose to use spread operator instead of appending .toList(). Something like:

ListView(
  // where items is from API
  children: [...items.map((i) => Text(i))],
)
  • Related