0

I read in this article http://www.adobe.com/devnet/flex/articles/flex-mobile-performance-checklist.html that I should not initialize a View's appearance in a creationComplete handler. Instead, I should change view's appearance in an overridden data setter.

The section in the article is:

Override the data setter instead of using bindings or initializing a View's appearance in a creationComplete handler

1-First, I would like to know if I got this right by doing the following:

//My code is loading a set of images and adding them in a View. 
//On creationComplete of the View I am adding the images in case this is the first time          
//the view is shown. In case the view has been already accessed I use the data:  

   protected function view1_creationCompleteHandler(event:FlexEvent):void
        {
            if(!data) //On first creation of the view I create the data object
            {
                data = new Object();
                data.imageArray = new Array(); //set an array that will cache my images.
                for(var i:int = 0; i<36;i++)
                {
                    var img:Image = new Image();
                    img.source = 'assets/0'+i.toString()+'.png';
                    container.addElement(img);
                    (data.imageArray as Array).push(img);//Override the data for next time!
                }
            }
            else//Next time use the save images
            {
                for(var ix:int = 0; ix<(data.imageArray as Array).length;ix++)
                {
                    container.addElement((data.imageArray as Array)[ix]);
                }
            }
        }

If I am doing this correctly, I would like to know which approach is best. The above one, or the next one I am going to show which uses the images contentLoader with caching and queuing enabled with a ContentCache:

  protected function view1_creationCompleteHandler(event:FlexEvent):void
        {
            {
                for(var i:int = 0; i<36;i++)
                {
                    var img:Image = new Image();
                    img.contentLoader = ldr;
                    img.contentLoaderGrouping = 'gr1';
                    img.source = 'assets/0'+i.toString()+'.png';
                    container.addElement(img);
                }

        }

<fx:Declarations>
    <s:ContentCache id="ldr" enableQueueing="true"
                    maxActiveRequests="1" maxCacheEntries="36"/>
</fx:Declarations>

Also if someone could tell me what is the contentLoaderGrouping for. I would be very grateful. Thanks a lot!!!

PS:By the way both approaches work. The first approach is instant while the second approach shows the images beeing added in a very smooth way which actually gives a cool effect.

Dave
  • 598
  • 2
  • 4
  • 17

1 Answers1

1

Neither. The point of the suggestion was to NOT alter the displaylist after creationComplete, which requires an additional update cycle. Instead you should inject the data property when you push your view on the stack, and initiate your changes in the setter. Using the ContentCache has nothing to do with it (and can sometimes cause additional overhead if not used correctly).

override public function set data(value:Object):void
{
    super.data = value;

    //this was poorly optimized, so I made it
    //a little better...

    var imageArray:Array = (value == null || value.imageArray == null)?
        null : value.imageArray as Array;

    if(imageArray == null) //On first creation of the view I create the data object
    {
        imageArray = new Array(36); //set an array that will cache my images.
        for(var i:int = 0; i<36;i++)
        {
            var img:Image = new Image();
            img.source = 'assets/0'+i.toString()+'.png';
            container.addElement(img);
            imageArray[i] = img;
        }

        super.data = {imageArray:imageArray}
    }
    else//Next time use the save images
    {
        var n:int = imageArray.length;
        for (var j:int = 0; j < n; j++) 
        {
            container.addElement(IVisualElement(imageArray[j]));
        }
    }
}

EDIT

I was mistaken about when the data property is set during the view life-cycle.

Here is how it works:

View Life-Cycle Diagram

So you are correct that container would be null at that point. I was going to write up an example for you, but I'm having trouble figuring out what your end goal is here. Is there a specific reason you are storing the images on the data property? I think what you might actually want to do is this:

private var _data:Object = {cache: new ContentCache()};

protected function show_clickHandler(event:MouseEvent):void
{
    this.navigator.pushView(views.MyView, _data);
}

And in the view...

<s:View xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:s="library://ns.adobe.com/flex/spark" title="MyView">

    <fx:Script>
        <![CDATA[
            import spark.components.Image;
            import spark.core.ContentCache;

            override protected function createChildren():void
            {
                super.createChildren();

                //you might want to do a sanity first check to make sure the 
                //data was passed in correctly...

                var cache:ContentCache = ContentCache(this.data.cache);

                for(var i:int = 0; i < 36; i++)
                {
                    var img:Image = new Image();
                    img.contentLoader = cache;
                    img.source = 'assets/0' + i.toString() + '.png';
                    container.addElement(img);
                }
            }
        ]]>
    </fx:Script>

    <s:VGroup id="container" />

</s:View>
drkstr101
  • 760
  • 1
  • 6
  • 23
  • Clear as water, thank you very much. The thing is that the container is not created yet. So the question now is how do you add components to the creation chain of a container, so he adds those components on creation rather than having a new update cycle. – Dave Nov 14 '13 at 13:26
  • My understanding is that the creation of MXML children happens a little bit after initialization, and before the data property is set for data driven containers. Is this not the case for the ViewStack? If so, you can override createChildren and initialize your data for the firt time there, and returning early in the data setter if container is null. – drkstr101 Nov 14 '13 at 14:19
  • Ok worked super. The override data definitely comes before the createChildren. You said that using the ContentCache could cause additional overhead. What if I used it on my added Images? Would it cause overhead then? – Dave Nov 14 '13 at 15:57
  • That's exactly it! Instead of saving the images on the data I save the ContentCache! It's perfect! And the smooth effect was coming from having the enableQueueing = true; on the ContentCache! By the way I saw that you were also making a comment to my question:http://stackoverflow.com/questions/19939794/flex-4-6-tabbedviewnavigator-tabbar-with-indication-of-more-items?noredirect=1#comment29719514_19939794 Do you know the answer? – Dave Nov 14 '13 at 17:55
  • I also have a situation where I would like to override data with components. I would like to know if there is a way to do it with a simple solution like this one. Should I make a question about it on SO. I would then comment here the link for the question and erase these comments. Just because there is no way in SO to ask direct questions to users. If you know the answer for that would you be interested? Thanks again. – Dave Nov 14 '13 at 18:00