使用IntelliJ IDEA 12进行Flex开发

时间:2012-12-26 21:15:36

标签: flex intellij-idea flash-builder

我使用Flex / Flash Builder已经很多年了。最新版本的Flash Builder(4.7)似乎遇到了很多问题,其中最大的问题是:

  • 在MXML中未检测到组件ID。例如,您不能查找组件ID的用法。将光标保持在组件的ID上甚至不会标记ID的出现。相反,它标记MXML中实际id个字的出现次数
  • 非常慢。

我正在认真考虑转移到IntelliJ IDEA 12,尤其是在阅读了许多经验丰富的Flex开发人员并对其进行推荐并推荐它之后。

我试了一下。我花了一些时间来研究IDE的新术语(由this doc和JetBrains非常有用的支持人员轻松完成)。

我能够使用Adobe Flex 4.6 SDK在IDEA中设置我的(大型)项目并使其编译得很好。但我注意到我的AS文件中突出显示了许多“错误”,这些错误实际上都是误报。

ActionScript编辑器似乎无法识别MXML中定义的对象。显然,这是IDEA中的一个已知错误(跟踪here)。 此错误已存在超过2年!

引用JetBrains支持人员:

  

我必须承认,突出显示不包含类的ActionScript文件,而是将mxml包含在<fx:Script source="some_file.as"/>中,这可能是IntelliJ IDEA代码突出显示的唯一薄弱环节。如果您将AS代码嵌入<fx:Script/>的CDATA而不是引用为外部*.as文件,则错误突出显示将消失。虽然我明白这并不总是需要的。

     

我担心修复程序不会进入12版本,因为版本很快就会发布并且修复程序风险太大。问题的优先级取决于投票和用户反馈。到目前为止,我们只有2票(http://youtrack.jetbrains.com/issue/IDEA-52598),因为修复非常复杂,我们仍然没有实现它认为这是一个罕见的用例。我希望在12.x更新版本中修复它。

我的项目非常庞大,拥有庞大的MXML文件,每个MXML都有更大的AS代码。因此,出于组织目的,我需要在逻辑上将它们拆分为更小的文件。因此,将AS代码与MXML合并是不切实际的。突出显示的错误错误会大大降低代码的可读性。此外,它不允许AS代码中的控制/命令 - 单击组件ID快速导航到MXML中的组件定义(顺便说一下,现在在FB 4.7中也被破坏,但是好在FB 4.6)。

遗憾的是,IDEA中的这个错误对我来说是一个交易破坏者。但我想知道其他Flex开发人员如何能够克服/解决这个看似严重的错误。

让我觉得难以置信的是,只有2个人受到了这个bug的影响,特别是有很多Flex开发人员推荐IDEA。也许我做错了什么?

所有Flex开发人员,我将非常感谢您的想法。

更新

这是对RIAStar优秀而详细解答的回应。但它并没有完全帮助我。让我解释为什么以及如何使用<fx:Script source>。我使用的是Flex 4.x,几乎只有Spark组件。

  • 假设一个全新的Flex项目。主要应用程序是MXML文件。
  • 在此MXML文件中,假设我有一个注册表单。
  • 在编辑表单(在每个字段中)时,假设我必须运行验证并仅在表单完全有效时启用提交按钮。这意味着我需要将更改事件处理程序分配给表单项。事件处理程序是AS代码。
  • 假设有一个用户名字段,需要通过异步调用服务器进行 on-type 唯一性检查。服务器通信代码也是AS代码。
  • 当然,还有提交按钮处理程序,它也是AS代码。

我通常将所有AS代码放在单独的.as文件中,并使用<fx:Script source>将其包含在MXML中。这个AS代码通常非常繁重,具有许多功能和行为逻辑。很多时候,基于用户操作,甚至MXML中的组件和元素的布局也会通过此AS代码进行修改。

如果我理解你们是对的,那么这些事件处理程序代码都不应该在这些MXML脚本文件中。那么,它应该在哪里?你们是怎么做到的?我不确定Spark Skinning架构与此有什么关系。

2 个答案:

答案 0 :(得分:14)

由于我想不出一个温和的方式,我只是直言不讳:我担心只有两个人认为这是一个关键的错误,是大多数经验丰富的Flex开发人员会同意使用<fx:Script source="some_file.as"/>是不好的做法 您有效地创建了两个代表一个类的文件。从您似乎关注的可读性POV来看,这不是一个好的举动。其中一个文件(.as文件)只是一堆本身不能存在的函数:它们与另一个文件/类紧密耦合,但只是查看.as文件,无法知道哪个类它耦合到。当然你可以使用某种命名约定来解决这个问题,但最后ActionScript / Flex应该被用作静态类型语言,而不是依赖于mixins和命名约定的脚本语言(不要误解我的意思) :我不是说脚本语言是不好的做法;它不是ActionScript的构思方式。

那你有什么选择呢?
我想这个结构背后的主要原因是你希望将MXML与ActionScript代码分开,或者用更抽象的术语分开:将视图与逻辑分开。幸运的是,这可以通过其他一些更清洁的方式实现。您可以使用哪些解决方案取决于我们是在谈论Flex 3(或更早版本)还是Flex 4。 我意识到你可能没有时间将你的代码重构为一个建议的解决方案,但我不想让你只留下“那不是很好的做法”的答案。

Flex 3(mx)

代码落后:许多开发人员使用所谓的“代码隐藏”模式将他们的逻辑与他们的观点分开。您可以通过Googling "flex code behind"找到有关该主题的大量信息。我不需要在这里重复所有这些。我不太喜欢这个概念,因为它很大程度上依赖于继承,而且两个结果类仍然紧密耦合,但至少我们说的是两个。如果你很好地设计你的架构,你甚至可以重用一些基类。

Compose model en controller:我曾经为每个MXML视图创建一个单独的“表示模型”类和一个“控制器”类,然后使用它:

<!--MyView.mxml-->
<mx:VBox>
    <m:MyModel id="model"/>
    <c:MyController model="{model}" view="{this}"/>
    ...
</mx:VBox>

MVC纯粹主义者不会喜欢这样,但在Flex应用程序的背景下,它对我来说非常好 后来,当直接注入支持框架(如Parsley)出现时,我可以使用注入来连接所有这些类,而不是像本例中那样硬连接它们。

MVC框架:我对这个主题的了解很少(因为在我看来,Flex是一个非常不错的MVC框架,不需要第三方添加,但这是另一个讨论),但简而言之:它们可以帮助您以清晰的方式将逻辑从视图中分离出来。

Flex 4(Spark)

使用Flex 4,引入了Spark皮肤架构,它允许非常好的分离视图和逻辑。您可以使用简单的ActionScript创建一个所谓的“主机组件”类,其中包含所有行为代码,MXML中的“外观”类定义了组件的可视化表示。这使得设计可重用组件非常容易。

根据您的要求,这是一个简化示例,说明如何使用Spark外观来创建注册表单。
让我们从皮肤类开始,因为它很容易理解。它只是一个包含一些输入字段的表单。 HostComponent元数据告诉皮肤它应该与SignUp主机组件一起工作。

<!--SignUpSkin.mxml: the visual representation-->
<s:Skin xmlns:fx="http://ns.adobe.com/mxml/2009"
        xmlns:s="library://ns.adobe.com/flex/spark">

    <fx:Metadata>
        [HostComponent("net.riastar.view.SignUp")]
    </fx:Metadata>

    <s:Form>
        <s:FormHeading label="Sign up"/>

        <s:FormItem label="User name">
            <s:TextInput id="userInput"/>
        </s:FormItem>

        <s:FormItem label="Password">
            <s:TextInput id="passwordInput" displayAsPassword="true"/>
        </s:FormItem>

        <s:Button id="submitButton" label="Submit" 
                  enabled="{hostComponent.canSave}"/>
    </s:Form>

</s:Skin>

现在主机组件采用纯ActionScript。它必须扩展SkinnableComponent以便能够使用我们的皮肤(我最近刚刚在这个问题中解释了SkinnableContainerFlex mxml custom component - how to add uicomponents?,但我们不需要这里)。

public class SignUp extends SkinnableComponent {

    [SkinPart(required="true")]
    public var userInput:SkinnableTextBase;

    [SkinPart(required="true")]
    public var passwordInput:SkinnableTextBase;

    [SkinPart(required="true")]
    public var submitButton:IEventDispatcher;


    [Bindable]
    public var canSave:Boolean;


    override protected function partAdded(partName:String, instance:Object):void {
        super.partAdded(partName, instance);

        switch (instance) {
            case userInput:
                userInput.addEventListener(TextOperationEvent.CHANGE, 
                                           handleUserInputChange);
                break;
            case passwordInput:
                passwordInput.addEventListener(TextOperationEvent.CHANGE, 
                                               handlePasswordInputChange);
                break;
            case submitButton:
                submitButton.addEventListener(MouseEvent.CLICK, 
                                              handleSubmitButtonClick);
        }
    }

    private function handleUserInputChange(event:TextOperationEvent):void {
        validateUsername(userInput.text);
    }

    ...

}

这里有什么重要的?
标记为SkinPart的变量将自动分配给您刚创建的外观中存在的具有相同ID的组件。例如,<s:TextInput id="userInput"/>将被注入public var userInput:SkinnableTextBase;。请注意,类型不同:SkinnableTextBaseTextInput的基类;这允许我们创建另一个皮肤,例如一个TextArea而不是TextInput,它可以在不触及主机组件的情况下工作 只要将SkinPart添加到显示列表中,就会调用partAdded(),这就是我们连接事件侦听器的位置。在这个例子中,我们在其值发生变化时验证用户名 验证完成后,您只需将canSave属性设置为truefalse即可。此属性的外观中的绑定将自动更新Button的enabled属性。

并同时使用这两个类:

<v:SignUp skinClass="net.riastar.skin.SignUpSkin"/>

答案 1 :(得分:0)

我实际上非常喜欢使用RobotLegs。

在我的MXML视图中,我尝试将所有逻辑保留在MXML之外,只是将事件发送给调解器。从那里我可以将代码放在调解器中,以满足更重的AS。