Flutter ListView.builder not updating after insert

Dev*_*ior 2 dart flutter flutter-layout

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]
    )
),
Run Code Online (Sandbox Code Playgroud)

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

小智 11

我遇到了类似的问题,我正在使用 StreamBuilder 监听 Floor db 更改,其中 StreamBuilder 正在做出反应,但 ListView 没有更新。尝试了上面的解决方案

child: new ListView.builder(
key: UniqueKey(),
Run Code Online (Sandbox Code Playgroud)

然后 ListView 用新数据进行更新,但有一个问题,在上面的实现中,ListView 被刷新,这对于添加新数据非常有用,但是当我更新数据库中的数据或使用可关闭小部件删除数据时,ListView 是再次刷新并显示第一个元素。

所以我尝试将密钥添加到 itemBuilder 中的每个小部件中,它对我有用

ListView.builder(
      padding: const EdgeInsets.all(8),
      itemCount: array.length,
      itemBuilder: (context, index) {
        return ListItemWidget(
          dao: dao,
          item: array[index],
          key: UniqueKey(),
        );
      },
    );
Run Code Online (Sandbox Code Playgroud)


Kir*_*hov 5

也许您应该将唯一密钥传递给自己MessageItem。当您收到数据时:

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

当您添加新条目时:

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

MessageItem构造函数中:

MessageItem(..., {Key key}): super(key: key);
Run Code Online (Sandbox Code Playgroud)

另一种方法是为列表指定一个随机密钥,如下所示:

  child: new ListView.builder(
    key: new Key(randomString()),
Run Code Online (Sandbox Code Playgroud)

您可以在https://flutter.io/widgets-intro/#keys中阅读有关键的信息,也可以查看Dismissible小部件作为示例