具有大量 UI 对象的 Flex 应用程序 == 慢?

Posted

技术标签:

【中文标题】具有大量 UI 对象的 Flex 应用程序 == 慢?【英文标题】:Flex app with large number of UI objects == slow? 【发布时间】:2010-11-01 16:32:46 【问题描述】:

我正在 Flex 3 中构建我的第一个 Flex 自定义组件。它是一个基于“网格”容器类的数据表,每个单元格中都有一个简单的文本标签。 (DataGrid 和 AdvancedDataGrid 不是我需要的合适起点。)该组件在使用较小的表时运行良好,但我尝试使用较大的表对其进行压力测试,结果令我失望。

组件创建过程有一些缓慢的地方,但这些都是我可以优化的,不是我主要关心的。更让我担心的是 Flex 框架本身的限制。

这个“大”样本表中有超过 7000 个单元格。这是较大的,但仍然比我需要容纳的最大数量少 1-2 个数量级。在标准 Grid 结构中,组件的主要部分由一个 Grid 组成,该 Grid 包含 400 个 GridRows,每个 16 个 GridItem,加上一些其他较小的辅助 Grid。

表格呈现后,我发现以下内容:

与鼠标相关的事件触发缓慢。具体来说,我在每个表格单元格上注册了 rollOver/rollOut 事件处理程序,让我突出显示指针下的单元格。在一张小桌子上,我可以很快地将鼠标移到桌子上,高亮会实时跟随指针。对于较大的表格,突出显示非常不稳定,每秒仅更改两次,跳过许多单元格。 如果我将鼠标光标放在组件上并将其留在那里,我的 CPU 将被锁定(无论如何是一个处理器内核),并一直保持这种状态,直到我离开组件,当它下降到空闲时。我的组件此时根本没有做任何事情。

感觉 Flex 根本无法扩展以支持这么大的组件树。我不寒而栗地想象它会如何处理 100,000 个细胞。也许我正在推动 Grid 超出其预期用途,但每个表格单元格有一个对象似乎不是一个不合理的模型,树中有大约 14,000 个对象(每个单元格一个 GridItem 和一个标签)似乎相当适中。

我还没有从 FlexBuilder 分析器中获得有用的数据;我在做这个工作。目前,我最大的问题是:

我真的通过这个适度的测试来突破 Flex 的极限吗? 我对这个组件的处理方法是否完全脱离了基础?

我在 WinXP 上的 Firefox 下的 Flash Player 9 上运行它。

【问题讨论】:

Eh... 对于任何小部件管理器来说,这种设计都会变得相当缓慢。您通常最好使用一种设计,该设计只为在任何给定时间点实际需要在屏幕上显示的内容创建元素,并根据需要填充它们以反映用户想要查看的内容(响应滚动、搜索等) 听起来重新考虑是为了......我希望用户能够以当前架构支持的方式无缝滚动浏览所有数据,但听起来我会必须手动管理而不是依赖框架。哦,好吧...我确实说过这是我的第一个 Flex 组件。 :) 您可以创建一个自定义滚动条,将新数据输入网格以模拟这种效果。这样你只需要数据,而 Flex 只分配一页所需的显示对象数量。 【参考方案1】:

是的,Flex 并不是为支持大量组件而设计的,众所周知,您应该尽量减少组件的数量并且不要使用您不需要的功能(例如,如果您使用 DisplayObject 而不是 Canvas不需要额外的功能)。

将数据与显示的对象完全镜像是不明智的。 DisplayObjects(和相关类)相对重量级,你需要控制你有多少。

我想说的是,您正在处理的规模,有 1000 多个单元,并且每个单元都有一个事件侦听器,肯定会达到 Flex 的限制。

我认为您应该更好地了解您的方法和架构。我假设您没有同时显示所有 1000 多个项目,也许您应该使用分页并在每个屏幕上显示 100ish,并使用上一个/下一个按钮移动到另一个页面。您还可以考虑使用自定义滚动条动态添加和删除行,模拟滚动效果。这要复杂得多。

【讨论】:

【参考方案2】:

男孩,看来我们可以写一本关于这个主题的书。或者至少一章。在开发产品时,我们在这方面学到了很多东西。

底线 - 是的,当您在屏幕上添加 1000 多个“事物”时,Flex 会减速到停止。以下是一些要点,以及已经提到的一些重复内容(为了简洁起见)

1) 始终只绘制可见的内容。新 Spark DataGrid 的架构师 Hans Muller 对 ViewPorts 有一篇精彩的文章。 http://hansmuller-flex.blogspot.com/2009/06/introduction-to-viewports-and-scrolling.html。所以实例化足够多的“单元格”来填充可见区域,并在用户滚动时基本上回收它们。

2) 回收、回收、回收:除此之外,当用户滚动时,您显然必须回收现在不在视野中的单元格以显示在视野中的单元格。这里有一些我们很难学到的东西:-) -> 与其处理和创建新单元格,不如使用重新父级或使用重新定位(首选重新定位)

这意味着:假设您有一个 10X10 网格(可见)显示一个 100X100 数据提供者。当用户滚动到 20X20 单元格时,最快的方法是将现有单元格的 X 和 Y 设置为新的位置,然后为每个位置调用集合数据。我们之前使用了reparenting,因为我们的场景是一系列相关的容器,所以这可能不适用于您。但底线 - 我们只是在可见区域周围移动“行”。所以创建和销毁会很慢,删除和添加到显示对象列表会更快,而只移动 (x,y) 会最快。

3) 明智地选择继承自什么:Flex SDK 是一头野兽。所以明智地选择你的“细胞”基类。例如,SDK DataGrids 有一个轻量级的渲染器,它继承自 UITextField (Halo),而不是 Label。甚至 UIComponent 在某些情况下也会很重。查找 UIComponent 的 asdocs 并查看您是否需要其中的所有内容,否则请考虑从其层次结构的更上层继承。

4) 缓存计算:在您的开发周期中最后执行此操作。完成功能后,运行 flex profiler。确定运行时间最长的方法和调用次数最多的方法。我们在发布时总是这样做,因为总是有改进的地方。在开发高度可视化的组件时会涉及大量数学运算,过多的计算会减慢速度。

5) 确保您的内存配置文件:无线事件侦听器、恶意对象引用等会影响性能。 Flex 分析器是解决此问题的绝佳工具,因此请务必使用它。

我们在这里有一些很好的链接: http://www.flexicious.com/resources/Ultimate/Docs/LargeDataset.htm?

希望这会有所帮助!

【讨论】:

不错的总结。最终,我们自己吸取了大部分教训,现在的表现相当不错。不过,关于分析器:我发现它与用于 Java 的 YourKit 相比是一个相当糟糕的工具。它似乎对追踪泄漏的物体几乎没用。我已经有一年的大部分时间不用接触 Flex,所以也许从那以后它得到了改进,或者我只是用错了。【参考方案3】:

如果您查看 Flex 框架中的任何基于列表的控件,您会发现它们大量使用了可回收的项目渲染器。因此,显示 20 行的 DataGrid 仅创建大约 22 个渲染器,并在您滚动列表时回收它们。这就是为什么 DataGrid 可以保存数千条记录并且仍然具有相当出色的性能的原因。我建议您查看 Peter Ent 关于项目渲染器的系列文章,并查看 ListBase/List 和一些相关类以了解如何构建类似的东西:

http://weblogs.macromedia.com/pent/archives/2008/03/itemrenderers_p.html

【讨论】:

【参考方案4】:

没有看到你的代码,也没有确切地知道你想要做什么......通过一次将这么多数据推送到框架中,你似乎正在推动 Flex 的极限。

请记住,Flash 运行时并不是为处理大型应用程序而设计的……而是在浏览器中运行一些轻量级的应用程序。您的用户似乎也不太可能需要同时访问所有这些控件。

您可以尝试提供数据服务(Java、.NET 等)来驱动应用程序中的数据。然后,您将对数据进行分页,以便框架一次只能处理 200 到 300 多个元素。

【讨论】:

【参考方案5】:

在 flex 中,如果你使用鼠标移动事件来重绘任何东西..你可能会经历非常慢的渲染。

例如:

this.addEventListener(MouseEvent.MOUSE_MOVE, redraw);

public function redraw(anything:Object=null):void
        //draw something here
            this.graphics.clear();
            this.graphics.lineStyle(3, 0x000000);
            this.graphics.moveTo(startPoint.x, startPoint.y);
            this.graphics.lineTo(endPoint.x, endPoint.y);
            this.scaleTextInput.x = centerPoint.x;
            this.scaleTextInput.y = centerPoint.y;

    

上面的代码导致渲染很慢......

解决方案:

改用 Event.ENTER_FRAME 事件?尽管比鼠标移动事件占用更多资源,但您每秒应该会收到更多更新,从而使鼠标对用户的响应速度更快:

例如:

this.addEventListener(Event.ENTER_FRAME, redraw);而不是

this.addEventListener(MouseEvent.MOUSE_MOVE, redraw);

你很高兴..Happy Flexing

更多信息: http://www.deepakdhakal.com

【讨论】:

以上是关于具有大量 UI 对象的 Flex 应用程序 == 慢?的主要内容,如果未能解决你的问题,请参考以下文章

如果需要 Beta Beta 功能,则将 Material-UI 的 beta 版本用于具有大量内容的长期 React Web 应用程序

如果beta beta功能是必需的,那么使用Beta版本的Material-UI可以获得具有大量内容的长期React Web应用程序

Flex:如何使用 Flex Builder 分析器对 UI 操作进行计时?

具有独立滚动列的材质 UI 网格

微信小程序:UI布局基础

微信小程序-学习笔记5-UI布局