Flex3里处理延误的实例化(I)

来源:互联网 发布:洪军杰淘宝店 编辑:程序博客网 时间:2024/05/16 19:17

本文来自:

http://www.insideria.com/2009/11/handling-delayed-instantiation.html

延误的实例化是Flex里的一个技巧,IContainer的子控件没有被创建,直到用户真正地需要看到它们。例如,如果你知道你的组件仅仅有前一半会显示,你可以控制添加到通过MXML的组件的子控件的创建,仅显示你知道会首先看到的那些。然后,当它们从上往下移动时,你可以看到其它的了。

Flex组件最为熟悉的一个使用延误实例化的范例就是ViewStack和它的子类, Accordion和 TabNavigator。在大部分情况下,ViewStack上的creatioPolicy会是“自动”的,这就意味着ViewStack的直接子控件会被马上创建。但是在大部分案例中,孙子控件是在特定的ViewStack面板被显示时创建的。通常情况下,这个过程很轻松,但是最近,我两次遇到”gotchas“:一个是当ViewStack包含了需要在其孙子控件上设定属性的Container子类,一次是当ViewStack的子控件由Repeater创建,而那些子控件包含了一个基于List的组件。

本周,我将讨论第一种情况,我将在下周讨论Repeater案例。对于这个问题的解决方案很简单。因此如果你时间比较紧,不想费劲去了解“为什么“。那现在就进入解决方案。

子类化Container不是那么难的-你只需要把Canvas, Box, VBox, 等作为你的AS类的子类或MXML的根标签使用。为简洁起见,我将参照一个假定拓展的VBox叫做VBoxWithComboBoxes。现在,comboboxes需要大量的设置。首先,它们需要一个dataProvider,这样你可以有几个选择。用数据绑定的方法就比较简单。但是,决定在combobox里选定内容的值很少与dataProvider里的条目精确映射,所以通常你不得不遍历dataProvider以寻找满足你的标准的条目,然后据此设定selecteditem或selectedindex。

这就导致了一个问题,因为一旦决定选定内容的值改变或dataProvider改变,你就需要进行此操作。没有深入组件的生命周期,因此我们不能确保当这些值的设值函被调用时,ComboBox的确存在。所以大部分开发人员在设值函数里调用invalidateProperties(), 设置一个标志(我们在commitProperties()可看到,覆盖),然后进行改变。通常,这个执行都会进行,因为commitProperties()常常在createChildren()之后被调用。

但是如何你像我一样,认为createChildren()结束时,所有的子控件已经被创建,你就可能错了。因为当利用延误的实例化创建一个容器时,子控件很有可能尚被创建。因此,这个挑战,子控件是否被创建了,就变得很关键。

我之前的研究显示,子控件肯定initialize()结尾时被创建。因此我的第一个想法就是,检查在commitProperties()里的初始化。这只有一个问题,就是,当我调用在设值函数里的commitProperties()时,被设定的验证标志已经在初始化完成时被清除,因此commitProperties()不会被调用。所以,我需要找到更有保证性的方法,确保在子控件没有被创建之前,我不会读取子控件。

为此,我不得不深入Container和ViewStack代码,我想,我最好做下总结。

a. 在UIComponent(是Container的基类),initialize() 调用createChildren();

b. Container覆盖createChildren(),调用一个新的函数createComponentsFromDescriptors()。这需要一个标志告知是否要递归子控件。当在Container内部调用时,这个标志通常是正确的。在函数结束时,它设定一个标量,processedDescriptors。该变量作为UICompoent里的一个设值函数。除了设定潜在的局部变量,这个设值函数产生一个事件,通知每个人容器被初始化。

c. ViewStack 覆盖createComponentsFromDescriptors,检查creationPolicy,然后针对creationPolicy, 设定递归标志。在此覆盖结,processedDescriptors变量也是正确的,但是记住,它仅仅是ViewStack的processedDescriptors变量(尽管,在第一个面板上的组件上,它也是正确的)。这就意味着如果我们的VBoxWithComboBoxes 是ViewStack的子控件,但是不是在第一个面板上,它的子控件就很可能不会被创建(我们将在下周讨论特例),它的processedDescriptors 变量也会是错误的,直到ViewStack告知它处理其子控件描述符。

d. ViewStack还有一个函数,instantiateSelectedChild(), 从ViewStack的其它地方被调用。当selectedIndex设值函数设定可能选择未被实例化的子控件的条件时,这个函数在commitProperties()。该函数然后调用createComponentFromDescriptors(),递归标志设定为正确,标志告诉我们的VBoxWithComboBoxes 创建子控件,然后processedDescriptors实例变量在创建的新VBoxWithComboBoxes上被设定为正确。

这个研究清楚地显示,我寻找的变量就是processedDescriptors。但是,我还是不确定覆盖什么以说服commitProperties() 运行。我的第一个选择是initialize(), 因此它更为简单的方法签名意味着我在调用super.initialize()时,不太可能把事情搞砸。然而,似乎编译器对于“不赞成”在Container子类里覆盖initialize(),因此我不再覆盖createComponentsFromDescriptors(), 仅仅是向invalidateProperties()增加了一个调用。所以,随着我的commitProperties覆盖,解决这个问题的代码就是:

 

【国内下载】Flex 3 Builder :http://g.csdn.net/5120749
【国内下载】Adobe Flash Builder 4 :http://g.csdn.net/5105812
【官方下载】Flex 3 Builder :http://g.csdn.net/5121278
【官方下载】Adobe Flash Builder 4 :http://g.csdn.net/5120750

原创粉丝点击