Goodbye and thank you, Flash Player, for all that jazz

July 27th, 2017

My adventure with Flash Player had started back in 2002 when I’ve explored the capabilities of this platform for the User Interface prototyping at Philips Research using Flash MX components and ActionScript 2.

 

 

One of my first commercial work was games development together with Sean Wood using Flash lite development for one Japanese mobile operator, later we’ve done together interactive maps app for Ayuquila river basin area for United Nations University.

My interest into the development of UI components using Flash platform had led to my collaboration with Judah Frangipane on Tree component with Drag and drop support.

Later I worked with Dmitry Leader on Re:mark application to be used by mentors for adding remarks to the reviewed documents, early days of the company that is now known as Grammarly.

Then we played with an idea on building audio player in Flash for ukrainian mobile operator Kyivstar and Anton Antropov.

In 2005 a group of ex-employees from Macromedia and Microsoft had established an startup in intriguing Ukraine to build on Web an user customized application built in Macromedia Flex 1.5 and later Adobe Flex 2, that’s how I did open an new chapter in my life with Flex UI framework.

I’ve spent with Flex UI framework almost 10 years of my development career, did a few talks at Ukrainian Flash User group, open-sourced InputAssist component, but after Adobe decision in 2011 to abandon the future development of Flex framework it become obvious that sooner or later every seasoned Flex developer has to move on.

Nowdays my choice of technologies for modern web application is React and Redux state container, Javascript with Ecmascript 6 touch, npm and many more.

Yes, we will say the final goodbye to Flash player runtime in 2020, but Web and UI interfaces will remain with us till the very end of our professional life.

When overriding “commitProperties” put “super.commitProperties” call to the end of the method

February 3rd, 2010

My use-case
   Recently I’ve tried to introduce skin states to the pretty complex UI component in Adobe Flex 4. I have got puzzled by the behaviour that my invalidateSkinState() calls never had triggered execution of getCurrentSkinState method that controlls the current UI component skin state value as expected.

[pullquote]Invalidation of the same phase while processing that phase is ignored – by Alex Harui[/pullquote]

   Under closer examination I found out that I fall into the same invalidation trap that James Polanco did in November 2010.

   I must stress out that it was easy to fall into this trap in my case because inside “commitProperties” call I was doing pretty complex calculations that involved, for example, the creation of display object sub-children, listening for “preinitialize” events from those sub-children, reacting to it, etc.

    To cut the talk short, to prevent this property invalidation trap from happening I suggest to always follow the simple rule of the thumb:

When overriding “commitProperties” put “super.commitProperties” call to the end of the method

override protected function commitProperties():void
{
    if (myPropertyChanged)
    {        
        disableMyUIComponent = true;
        invalidateSkinState();
        myPropertyChanged = false;
    }
    super.commitProperties();
}
 
override protected function getCurrentSkinState():String { 
    var returnState:String = "normal"; 
 
    // Use information in the class to determine the new view state of the skin class. 
    if (disableMyUIComponent)     { 
        returnState = "disabled"; 
    } 
    return returnState; 
}

Futher reading:
Discussion at 2008 at Flexcoders mailing list (yeah, at that time, this mailing list was more interesting to read) “Must call super.commitProperties at END of overrided commitProperties when extending XXXX?”

When it is time to reset dirty flag “invalidatePropertiesFlag” in Flex invalidation framework?

December 24th, 2009

   Invalidation in Flex is a mechanism by which changes made to a component’s property values are queued and postponed for the final procession till the end of the current Flash movie frame play. This property value invalidation mechanism in Flex is controlled by setting and resetting boolean variables called dirty flags.

   One of such a dirty flags used internally in Flex invalidation mechanism is invalidatePropertiesFlag flag.

   This particular flag is reset in validateProperties() method from mx.core.UIComponent class from Flex 3 SDK:

public function validateProperties():void
{
    if (invalidatePropertiesFlag)
    {
        commitProperties();
        invalidatePropertiesFlag = false;
    }
}

   Inside commitProperties() function the actual change occur to the invalidated property’s value, for example, it can be “width” property.

   The question is – why dirty flag invalidatePropertiesFlag is reset after call to commitProperties() method, but not before this call?

    My far-fetched speculation is that this had happened because:

  • It is just a matter of life == code convention to put the dirty flag at the end of IF block;
  • If code within commitProperties() raises RTE, we will still have a chance to execute the code in commitProperties() during playing next frame in Flash Player and this time maybe the code will not throw RTE.

   At this point, you may start to wonder why the exact location (at the very beginning or at the very end of IF sequence) of the dirty flag can be important?

   The reason is:

   If the code within commitProperties() implementation will try to invalidate some other component’s property (e.g “height” property) that tries to invoke another invalidation routine by using dirty flag, then this invalidation call will not be added to mx.managers.LayoutManager.invalidatePropertiesQueue, because dirty flag invalidatePropertiesFlag is still equal to true, see the listing of invalidateProperties method from UIComponent for the method logic:

public function invalidateProperties():void
    {
        if (!invalidatePropertiesFlag)
        {
            invalidatePropertiesFlag = true;
 
            if (parent && UIComponentGlobals.layoutManager)
                UIComponentGlobals.layoutManager.invalidateProperties(this);
        }
    }

NEVER use selectable=false for editable List or DataGrid Flex components

June 15th, 2009

It is very likely that the authors of Adobe Flex SDK have never devised the following simple use-case for both List and DataGrid components from Flex SDK:

  • “selectable” property is set to false
  • “editable” property is set to true

    To prove this fact, try to play with the following samples:

    mx:List

    Get Adobe Flash player

    Click the first row, in a List, then the itemEditor appears on the first row.
    Click the second row in a List , but the itemEditor doesn’t appear on the second row

    That’s bug SDK-15309, documented over year ago.

    mx:DataGrid

    Get Adobe Flash player

    Code listing:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    
    <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
                    creationComplete="initApp();"
                    width="400"
                    height="300"
                    styleName="plain"
                    paddingLeft="0"
                    paddingRight="0"
                    paddingTop="0"
                    paddingBottom="0">
     
        <mx:Script>
            <![CDATA[
                import mx.events.DataGridEvent;
     
                private function initApp():void {
                    dg.dataProvider =                     [
                        {Artist:'Carole King', Album:'Tapestry', Price:11.99},
                        {Artist:'Paul Simon', Album:'Graceland', Price:10.99},
                        {Artist:'Original Cast', Album:'Camelot', Price:12.99},
                        {Artist:'The Beatles', Album:'The White Album', Price:11.99}
                        ];
                }
     
                private function onItemEditBegin(event : DataGridEvent) : void
                {
                    trace ("DG onItemEditBegin");
                }
     
            ]]>
        </mx:Script>
        <mx:DataGrid id="dg"
                     rowHeight="20"
                     editable="true"
                     selectable="false"
                     width="100%"
                     height="100%"
                     itemEditBegin="onItemEditBegin(event)">
            <mx:columns>
                <mx:DataGridColumn
                                   dataField="Artist"
                                   width="100">
                </mx:DataGridColumn>
                <mx:DataGridColumn
                                   dataField="Album"/>
                <mx:DataGridColumn
                                   dataField="Price"/>
            </mx:columns>
        </mx:DataGrid>
    </mx:Application>

    Now, try to click on the DataGrid header, oops, you’ve just hit SDK-19436 bug (itemEditor instance is created unwillingly at first column, first row of DataGrid).

    Then try to scroll the DataGrid with scroller buttons, and again you’ve hit another, albeit similar, SDK-21726 bug (itemEditor instance is created unwillingly at first column, first row of DataGrid).

    Now scroll the contents of Datagrid a little bit down with a scroller thumb and start to edit cell in the first topmost visible row, first column, now move the current focus by pressing keyboard combination Shift+Tab, and once again, you’ve hit a SDK-16262 bug.

    To conclude this post: do not set selectable on mx:List or mx:DataGrid components to false if you are going to edit their values using itemEditors, until all above mentioned bugs will be fixed.

  • Always keep an eye on most recent stable release of Adobe Flex SDK

    November 4th, 2008

       I was going to enter a new issue into Adobe JIRA Flex SDK bugbase that I could confirm to be present in the most recent milestone Adobe Flex SDK release 3.1.0.2710, shipped together with an August 2008 Flex Builder 3.0.1 update.

       Just before submitting the bug issue, I’ve tested the functionality under the question under the latest Adobe Flex SDK stable build (3.2.0.3794 at the time of writing) – and I was surprised to find out that the bug is already fixed. Joy! Joy!

        I rushed to find the reasoning for this change for UITextFormat class by reading change notes at Flex SDK download section at Adobe open source web-site, but could not find any remarks regarding this change – would be handy to have a better insight behind this change for the community.

       ps If you wonder, the issue was incorrect implementation of an internal function copyFrom from UITextFormat class. UITextField’s public getUITextFormat() method relies on this copyFrom function to return UITextFormat object for the UITextField class instance. In a nutshell UITextFormat object is just a wrapper around textFormat class that should contain all the properties from wrapped textFormat class instance + add some additional functionality.

       As it turned out, In Adobe Flex SDK 3.1 and below, 7(!) different properties were not copied into UITextFormat object from existing textFormat format object because of wrong implementation of UITextFormat.copyFrom function.

       Now, we are safe, this particular issue is fixed!

    Hint: Always better to use ‘itemUpdated’ method instead of ‘setItemAt’ when updating existing items in ArrayCollection

    April 20th, 2008

       When you want to update already existing data item in your ArrayCollection in ActionScript 3 with a new values for object’s properties you have 2 options to select from:

    1. use itemUpdated(obj) ArrayCollection’s method.
    2. use setItemAt(obj, index) ArrayCollection’s method.

       ActionScript code sample:

        //Update an existing person in the ArrayCollection via setItemAt
     
        public function updatePersonViaSetItemAt():void {
            var currentlySelectedItem : Object = dg.selectedItem;
            currentlySelectedItem.first = firstInput.text;
            currentlySelectedItem.last = lastInput.text;
            ac.setItemAt(currentlySelectedItem, dg.selectedIndex);
        }
     
        // Update an existing person in the ArrayCollection via itemUpdated
     
        public function updatePersonViaItemUpdated():void {
            var currentlySelectedItem : Object = dg.selectedItem;
            currentlySelectedItem.first =  firstInput.text;
            currentlySelectedItem.last =  lastInput.text;
            ac.itemUpdated(currentlySelectedItem);
     
        }

       Which one to choose?

       I would strongly advice to always use ‘itemUpdated’ because of the following reasons:

    • Calling setItemAt(x) on your existing data item in ArrayCollection is an equivalent to calling the removeItemAt(x) method and then calling the addItemAt(…, x) method on your data item.
         Thus after making the call to setItemAt(x, index) you will loose the current selection in your ArrayCollection dependant UI component (mx:DataGrid, mx:Tree, mx:Combobox.. etc..)

    • If the Sort rule is already applied to your ArrayCollection then you can receive some funky results like unwanted inserting of a new row when partly changing several properties of the existing data item in ArrayCollection.

       Interactive sample with “View source” option enabled to watch the difference:
    http://jabbypanda.com/labs/updateArrayCollectionItem/updateArrayCollectionItem.html

    You can try the following:

    1. First apply sorting to any of the DataGrid’s column
    2. Select the first row in the Datagrid
    3. Rename the surname of the person to something completely new starting with a new letter
    4. Press “Update via setItemAt()” button control

    Voilà, new unwanted row becomes visible in the Datagrid.

    How to hide the unwanted content visible outside of mx:SWFLoader boundaries

    February 13th, 2008

    The issue:

    I was stumbled upon once ago when I loaded my external SWF file authored by the Flash IDE by the help of component and suddenly (?) every content object that was originally placed outside of the Stage inside the Flash IDE became visible in my Flex 2 based web application outside of the boundaries after loading sequence for my external SWF file was over (the file is Flash8 based, AVM1 if this matters).

    The corresponding task in Adobe JIRA bug-database:
    http://bugs.adobe.com/jira/browse/SDK-14590

    I currently fight this issue by applying the mask over the content that is loaded by the component, see the code below, may be you can find it helpful too:

    [sourcecode language=”xml”]
    <?xml version="1.0" encoding="utf-8"?>
    <mx:VBox xmlns:mx="http://www.adobe.com/2006/mxml"
    resize="applyMask()" >

    <mx:Script>
    <![CDATA[
    private function applyMask() : void {
    if (swf != null &&
    swf.content != null &&
    swf.content.loaderInfo.width > 0 &&
    swf.content.loaderInfo.height > 0) {
    var scaleRatioX : Number = swf.content.loaderInfo.width /
    this.width;
    var scaleRatioY : Number = swf.content.loaderInfo.height /
    (this.height – this.controlBar.height);
    var scaleRatio : Number = Math.max(scaleRatioX, scaleRatioY);

    swf.width = swf.content.loaderInfo.width > 0 ?
    Math.round(swf.content.loaderInfo.width / scaleRatio) : 100;
    swf.height = swf.content.loaderInfo.height > 0 ?
    Math.round(swf.content.loaderInfo.height / scaleRatio) : 100;

    var s : Shape = new Shape();
    s.graphics.beginFill(0xFFFFFF);
    s.graphics.drawRect(0, 0, swf.width, swf.height);
    s.graphics.endFill();
    swf.addChild(s);
    s.visible = false;
    swf.mask = s;
    }
    }
    ]]>
    </mx:Script>
    <mx:SWFLoader id="swf"
    complete="applyMask()"
    source="navigation.swf"/>
    </mx:VBox>
    [/sourcecode]