Flutter 聊天列表更新重建效率

问题描述

我是 Flutter 的新手,我正在尝试构建一个聊天应用程序,我看过几个教程。要查看聊天消息列表/历史记录,几乎每个教程都在做这样的事情:(我正在缩短代码以切入要点)

List<Widget> messages = api.listofMessages();

return Column(children: messages);

现在每次有新消息时,都会更新 messages 并重新构建列。我得说“重建”这个词对我来说听起来很昂贵。假设 2 个用户已经聊天 500 行。现在,每次收到新消息时,都会重新构建 500 行。

我想在列表的末尾放一个空的小部件。因此,当新消息到达时,我只需将其插入到那个空的小部件中,然后只重建它:

List<Widget> messages = api.listofMessages();

return Column(children: [...messages,EmptyWidgetForNewMessage()];

但这看起来像一个黑客,会导致很多嵌套的小部件,因为每条新消息还必须插入另一个 EmptyWidget 等...

如何避免重建以前的消息而只将新消息插入到视图中? (或者重建整个列表没什么大不了的?)

解决方法

您可以使用 sliver 小部件构建在视口(或 cacheExtent)中可见的消息。 像 ListView.build,ListView.separated,来自 ListView.build 的文档:

如果列表视图的子视图是 提前创建,或者在创建 [ListView] 本身时一次性创建, 使用 [ListView] 构造函数更有效。然而,更有效的是使用此构造函数的 itemBuilder 回调按需创建实例。

此外,我们不会一次从服务器获取所有消息。相反,我们将使用 ?page=1&size=20 之类的查询批量获取它们。

注意:此小部件存在一个已知问题,请尽可能避免使用 shrinkWrap: true。见this issue

,

您可以针对的几个改进

  1. 使用 ListView 构建器构造函数而不是列,只会呈现当前在屏幕中可见的子小部件,而在 Column 小部件中,将呈现其所有子小部件。此外,ListView 应该是您首选的小部件,因为 Column 小部件不可滚动,如果消息列表长度很大,则可能会出现溢出异常。

  2. const 返回的所有类型的小部件使用 api.listOfMessages() 构造函数,这将允许编译器重用任何呈现的小部件,这意味着每次发生状态更改时(在你的情况下到达新消息)整个树不会重新渲染,渲染器将可以重新使用以前构建的消息小部件。

这两个建议应该可以解决任何性能瓶颈,简而言之,我们将仅使用 ListView 呈现可见的子小部件,并且我们将在 const 构造函数的帮助下重用已呈现的小部件。