【问题标题】:Flutter ListView.builder not updating after insertFlutter ListView.builder 插入后不更新
【发布时间】:2018-07-11 07:29:33
【问题描述】:

我有一个 SQLite 数据库,可以从中查询数据。从这些数据中,我创建了必要的小部件并将它们存储在一个列表中。将列表传递给 ListView.builder 我从列表中创建项目。一切看起来都不错,除非我将新数据添加到小部件列表中。如果我使用insert,什么都不会显示。如果我使用add 没有问题。这是sn-p。

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 医生的说法,一切正常,感谢您的帮助 ;-)

【问题讨论】:

  • 什么是_messagesInsert(0, new MessageItem)?应该是_messagItems(0, new MessageItem());
  • @GünterZöchbauer 对不起,这是我评论中的一个懒惰的错字。我确实按照你的建议做。
  • 无法想象为什么它不起作用。

标签: dart flutter flutter-layout


【解决方案1】:

也许您应该将唯一的密钥传递给您的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 小部件作为示例

【讨论】:

  • 谢谢,我会看看这是否有效。我没有发布整个代码只是因为它有点长;)
  • 对此有一些问题,我将更新问题以显示发生了什么。
  • 添加密钥确实解决了这个问题。我只是没有意识到我必须将值转换为 Key 对象(呃!)。谢谢您的帮助! ;)
  • 哦,我会在我的回答中修复它:)
  • Aaaaaaaaaah,这行得通,非常感谢。我花了几天时间试图了解为什么列表正在更新,而不是视图;传递一个独特的密钥效果很好。再次非常感谢。
【解决方案2】:

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

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

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

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

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

【讨论】:

  • 非常感谢@Amal Paul,因为这个错误,只浪费了 3 小时,添加 key: UniqueKey() 修复它并强制 ListView.Builder 重建 UI。
猜你喜欢
  • 2019-08-19
  • 2020-10-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-04-16
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多