Flutter ListView.builder 插入后不更新

Flutter ListView.builder not updating after insert

我有一个从中查询数据的 SQLite 数据库。根据这些数据,我创建了必要的小部件并将它们存储在列表中。将列表传递给 ListView.builder 我从列表中创建项目。一切看起来都很好,除了我向小部件列表添加新数据时。如果我使用 insert,则不会显示任何内容。如果我使用 add 就没有问题。这是片段。

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]
    )
),

根据 Flutter 医生的说法,一切正常,感谢您的帮助 ;-)

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

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

添加新条目时:

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

MessageItem构造函数中:

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

另一种方法是为列表指定一个随机键,像这样:

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

您可以阅读 https://flutter.io/widgets-intro/#keys 中的键或查看 Dismissible 小部件作为示例

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

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

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

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

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