Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Flutter ListView.builder not updating after insert

I've got a SQLite database that I query data from. From such data I create the necessary widgets and store them in a list. Passing the list to ListView.builder I create the items from the list. Everything looks good except when I add new data to the widget list. Nothing shows up if I use insert. If I use add there's no issue. Here's the snippet.

List<MessageItem> _messageItems = <MessageItem>[];


// Reads the data and creates the widgets (all OK here)
// Called when reading the data <<<
_readDBMessages() async {
    List<Map> messages = await readMessages(_threadID);
    List<MessageItem> holderList = <MessageItem>[];
    for (final msg in messages) {
        holderList.add(new MessageItem(
            msg['message'],
            msg['timestamp'],
            msg['status'],
            _contactData['photo']));
    }

    _messageItems.clear();
    setState(() {
        _messages = msges;
        _messageItems = holderList;
    });
}


// When I use _messageItems.add(new MessageItem()); the item shows as expected but it
// it's located on top of the list. Since my ListView is reverse
// I instead use _messagesInsert(0, new MessageItem()); in doing so
// The list is not updated. Scrolling up/down will than proceed to
// show the item as expected.
// Called when storing the data <<<

_storeNewMessage(String message) {
    int timestamp = new DateTime.now().millisecondsSinceEpoch;
    storeMessage(_threadID, message, _me, 'sending', timestamp, 'text').then((onValue) {
            // _readDBMessages();
            setState(() {
                _messageItems.add(
                    new MessageItem(
                        message, timestamp, 'sending', null
                    )
            );

            print('Message inserted ---------------');
        });
    });
}


// Here's my listView constructor <<<
new Expanded(
    child: new ListView.builder(
        reverse: true,
        padding: const EdgeInsets.all(12.0),
        itemCount: (_messageItems == null) ? 0 : _messageItems.length,
        itemBuilder: (context, i) => _messageItems[i]
    )
),

According to Flutter doctor everything is OK, Thanks for the help ;-)

like image 432
DevilWarrior Avatar asked Jul 11 '18 07:07

DevilWarrior


People also ask

What is the difference between ListView and ListView builder flutter?

The main difference between ListView and ListView. builder is that ListView creates all items at once, whereas the ListView. builder() constructor creates items when they are scrolled onto the screen.

What is Itemextent in ListView builder?

It constrains its box children to have a specific given extent along the main axis. The prototypeItem property, which allows forcing the children's extent to be the same as the given widget.


2 Answers

Perhaps you should pass a unique key to your MessageItem. When you receive a data:

new MessageItem(
            msg['message'],
            msg['timestamp'],
            msg['status'],
            _contactData['photo'],
            key: Key(msg['message']+msg['timestamp'].toString())
            )

When you add a new entry:

        _messageItems.add(
            new MessageItem(
                message, timestamp, 'sending', null, key: Key("${message}${timestamp}")
            )
    );

In MessageItem constructor:

MessageItem(..., {Key key}): super(key: key);

Another way is to specify a random key for the list, something like this:

  child: new ListView.builder(
    key: new Key(randomString()),

You can read about the keys in https://flutter.io/widgets-intro/#keys or check Dismissible widget as an example

like image 124
Kirill Shashov Avatar answered Oct 05 '22 03:10

Kirill Shashov


I had a similar problem where I was listening to Floor db changes with StreamBuilder, in which the StreamBuilder was reacting but ListView was not getting updated. Tried the above solution

child: new ListView.builder(
key: UniqueKey(),

The ListView was then getting updated with new data but there was one problem, in the above implementation the ListView gets refreshed which works great with new data additions, but when I update a data in db or remove a data using dismissible widget, the ListView is again refreshed and the first element is displayed.

So I tried adding the key to each widget in the itemBuilder and it worked for me

ListView.builder(
      padding: const EdgeInsets.all(8),
      itemCount: array.length,
      itemBuilder: (context, index) {
        return ListItemWidget(
          dao: dao,
          item: array[index],
          key: UniqueKey(),
        );
      },
    );
like image 45
Amal Paul Avatar answered Oct 05 '22 04:10

Amal Paul