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

时间:2009-06-10 02:51:11

标签: flex flash actionscript-3 flex3

我正在使用Flex 3构建我的第一个Flex自定义组件。它是一个基于'Grid'容器类的数据表,每个单元格中都有一个简单的文本标签。 (DataGrid和AdvancedDataGrid不适合我的需求。)该组件使用较小的表可以很好地工作,但我尝试使用更大的表对其进行压力测试,并对结果感到失望。

组件创建过程有一些慢点,但这些是我的优化能力,并不是我主要关心的问题。让我更担心的是Flex框架本身的限制。

这个“大”样本表中有超过7000个单元格。这比较大,但仍比我需要容纳的最大量级低1-2个数量级。在标准网格结构中,组件的主要部分包含一个网格,每个网格包含400个GridRows,每个网格项目包含16个GridItem,以及一些其他较小的辅助网格。

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

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

感觉Flex似乎无法扩展以支持这么大的组件树。我不禁想象它会如何表现100,000细胞。也许我正在推动网格超出其预期用途,但是每个表格单元格中的对象看起来不像是一个不合理的模型,树中的~14,000个对象(GridItem和每个单元格的标签)看起来相当适中。

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

  • 我是否真的通过这种适度的测试来推动Flex的极限?
  • 我对这个组件的处理方式是完全偏离基础吗?

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

5 个答案:

答案 0 :(得分:7)

是的,Flex不是为支持非常大量的组件而设计的,众所周知,您应该最小化组件数量,不要使用您不需要的功能(例如,如果你使用DisplayObject而不是Canvas不需要额外的功能)。

使用显示的对象精确镜像数据是不明智的。 DisplayObjects(和相关的类)相对较重,你需要控制你拥有的那些。

我会说你正在工作的规模,1000+ Cell,以及每个Cell的事件监听器,肯定会达到Flex的极限。

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

答案 1 :(得分:6)

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

底线 - 是的,当你在屏幕上添加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设置为新位置,然后为每个调用集数据。我们之前使用过重新渲染,因为我们的场景是一系列相关容器,因此这可能不适用于您。但是底线 - 我们只是在可见区域周围移动“行”。因此创建和销毁会很慢,删除和添加到显示对象列表会更快,只需移动(x,y)将是最快的。

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

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

5)确保你对内存进行了分析:无线事件监听器,恶意对象引用等会破坏性能。 Flex Profiler是一个很好的工具来解决这个问题,所以一定要使用它。

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

希望这有帮助!

答案 2 :(得分:3)

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

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

答案 3 :(得分:1)

没有看到你的代码并且确切地知道你正在尝试做什么......看起来你似乎是通过一次性将大量数据推入框架来推动Flex的极限。

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

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

答案 4 :(得分:0)

在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);

你很高兴..快乐的弯曲

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