Flex:NPE和在创建完成之前访问组件属性的正确方法

时间:2013-12-09 22:45:44

标签: flex flex4 flex3

我认为我遗漏了一些关于flex sdk组件生命周期的重要内容,但是虽然阅读了很多教程,但是无法对其进行排序。您能否分享一下您如何使用flex可视对象属性进行操作的经验,以及在组件创建完成之前如何在访问NPE时避免使用NPE。 假设我们有一个简单的组件 MyTitleWindow.mxml

<s:TitleWindow>
    <s:DataGrid id="myDataGrid" />
</s:TitleWindow>

另一个组件从远程对象获取数据,并希望将数据应用到标题窗口的datagrid并通过PopUpManager显示:

 private function handleDataReceived(data : ArrayCollection) : void {
            var myTitleWindow : TitleWindow = new MyTitleWindow();
            PopUpManager.addPopUp(myTitleWindow);
            myTitleWindow.myDataGrid.dataProvider = data;
        }

当然,行 myTitleWindow.myDataGrid.dataProvider = data 会抛出一个NPE,因为我们正在尝试访问尚未渲染的myDataGrid。

目前我只能看到两种选择如何避免NPE:

  1. 在titleWindow中为数据创建一个setter,将数据放入一些 缓存。收听creationComplete事件,在它的处理程序中应用数据 从缓存到数据网格。这种方法很好,但我是 厌倦了在整个应用程序中添加这个安全防护。
  2. 制作一个     bindable属性 - 仅适用于简单数据类型     (数字,字符串......)
  3. 在使用flex验证/失效循环方面是否有任何遗漏可能有助于避免过多的代码?

3 个答案:

答案 0 :(得分:1)

你遇到的问题和Crusader的报告是因为在Flex组件中初始化是懒惰的。这通常是一件好事,但在你的情况下,它会导致你的问题。

一般情况下,我不建议在组件外部的视图组件上设置dataProvider,因为您无法知道是否所有设置都已准备就绪。

我通常做的事情。在简单的情况下,我只是添加一个公共propberty我做[Bindable]。 (我认为)更干净的方法是创建一个setter(和getter),然后将dataProvider保存在局部变量中(在你的情况下可能是ArrayCollection)。在setter中我经常检查&#34; myDataGrid&#34;存在,如果存在,则另外设置dataProvider属性。然后我会在我的组件中添加一个CreationComplete回调,并且我也会设置dataProvider。

因此,在组件初始化之前设置dataProvider时,该值将简单地保存在局部变量中,并且一旦完成设置,就会自动设置dataProvider。如果组件已经全部设置(您正在更改dataProvider),则setter将自动更新&#34; myDataGrid&#34;的数据提供者;

<s:TitleWindow creationComplete="onCreationComplete(event)">

    ...

    private var myDataProvider:ArrayCollection;

    private function onCreationComplete(event:FlexEvent):void {
        myDataGrid.dataProvider = myDataProvider;
    }

    public function set myDdataProvider(myDataProvider:ArrayCollection):void {
        myDataProvider = myDataProvider;

        // Only update the dataProvider if the grid is available.
        if(myDataGrid) {
             myDataGrid.dataProvider = myDataProvider;
        }
    }

    ....

    <s:DataGrid id="myDataGrid" />

</s:TitleWindow>

答案 1 :(得分:0)

是的,这可能是一种烦恼,而且不只是弹出窗口。使用具有默认创建策略的ViewStack组件时也会很痛苦,我倾向于经常这样做。

我可能因此而受到抨击,但我通常只使用绑定。我不确定你的“简单数据类型”是什么意思 - 它也适用于自定义类型。你必须提供一个例子。

你可以做的一件事(我可能可能因此而受到伤害:p)是在早期创建你的弹出组件实例并重新使用它而不是每次都创建一个新实例。

不,我不认为你在组件生命周期中“遗漏了什么”。

答案 2 :(得分:0)

我总是试图颠倒设置dataProvider的责任,并希望让组件观察[Bindable]集合。

在像你这样的简单例子中,我避免给我的组件id。这可以防止我通过外部引用封装破坏封装。

<s:TitleWindow>
    <s:DataGrid dataProvider="{data}" />
</s:TitleWindow>

MyTitleWindow 组件的使用者不应该知道它有一个ID为'myDataGrid'的DataGrid,或者需要设置'myDataGrid'的dataProvider属性。

考虑在MXML中声明的组件需要一个无争论构造函数(并且我们无法声明多个构造函数) - 过去一种对我有用的方法是提供静态的“newInstance”方法。我根据我正在使用的域以及任何必需的参数为此方法提供相关名称。

public static function withData(data : ArrayCollection) : MyTitleWindow
{
    var myTitleWindow : MyTitleWindow = new MyTitleWindow();
    myTitleWindow.data = data;

    return myTitleWindow;
}

这清楚地将我的组件的“合同”传达给任何和所有消费者。 (显然,通过更相关的命名,事情会变得更清晰。)

private function handleDataReceived(data : ArrayCollection) : void 
{
    PopUpManager.addPopUp(MyTitleWindow.withData(data));
}