Flex app with large number of UI objects == slow? - apache-flex

I'm building my first Flex custom component, in Flex 3. It is a data table based on the 'Grid' container class, with a simple text Label in each cell. (DataGrid and AdvancedDataGrid were not appropriate starting points for my needs.) The component works quite well using smallish tables, but I tried stress-testing it using a larger table, and have been disappointed by the results.
The component creation process has some slow spots, but those are in my power to optimize and aren't my primary concern. What worry me more are what appear to be limitations in the Flex framework itself.
This 'large' sample table has a bit over 7000 cells in it. This is largish, but still 1-2 orders of magnitude less than the biggest I need to accommodate. In standard Grid structure, the main portion of the component consists of a Grid with 400 GridRows of 16 GridItems each, plus a few other smaller ancillary Grids.
Once the table renders, I find the following:
Mouse-related events are slow to fire. Specifically, I have rollOver/rollOut event handlers registered on each table cell, to let me highlight the cell under the pointer. On a small table, I could move the mouse over the table very quickly, and the highlighting would follow the pointer in real-time. With the larger table, the highlighting is very jerky, changing only about twice per second, skipping over many cells.
If I place the mouse cursor over the component and leave it there, my CPU is pegged (one processor core, anyway), and stays that way until I move off of the component, when it drops to idle. My component isn't doing anything at all at this point.
It feels like Flex simply cannot scale to support component trees that are this large. I shudder to imagine how it would behave with 100,000 cells. Perhaps I'm pushing the Grid beyond its intended use, but having an object per table cell doesn't seem like an unreasonable model, and ~14,000 objects in the tree (a GridItem and a Label per cell) seems pretty modest.
I have yet to get useful data out of the FlexBuilder profiler; I'm working on it. For now, my biggest questions are:
Am I really pushing the limits of Flex with this modest test?
Is my approach to this component completely off-base?
I'm running this on Flash Player 9 under Firefox on WinXP.

Yes, Flex is not designed to support very large numbers of components, it is well known that you should minimize the number of components and don't use features that you don't need (Eg. DisplayObject instead of Canvas if you don't need the extra functions).
It's unwise to mirror your data exactly with displayed objects. DisplayObjects (and related classes) are relatively heavyweight, and you need to control how many of those you have.
I would say that the scale you're working at, with 1000+ Cells, and an event listener for each one, would definitely reach Flex's limits.
I think you should take a better look at your approach and architecture. I assume you are not displaying all 1000+ items at the same time, perhaps you should use paging and display 100ish with each screen, with previous/next buttons to move on to another page. You could also consider dynamically adding and removing rows using a custom scrollbar, simulating the scroll effect. This is much more complicated to do.

Boy, it seems we can write a book on this topic. Or atleast a chapter. We learnt quite a few things in this area as we were developing our products.
Bottom line - yes, Flex will slow down to a halt when you add 1000+ "things" on the screen. Here are a few bullet points, and some repetitions of what's already mentioned (just to be concise)
1) Always draw only what is visible. Hans Muller, the architect on the new Spark DataGrid has a great writeup on ViewPorts. http://hansmuller-flex.blogspot.com/2009/06/introduction-to-viewports-and-scrolling.html. So instantiate enough "cells" to fill up the visible area, and basically recycle them as the user scrolls.
2) Recycle, recycle, recycle: Further to above, as the user scrolls, you obviously have to recycle cells that are now out of view to show the ones that are in view. Here there are a few things we learned the hard way :-)
-> Instead of disposing and creating new cells, either use reparenting or use repositioning (prefer repositioning)
What this means is this: Say you have a 10X10 grid (visible) showing a 100X100 data provider.When the user scrolls to cells 20X20, the quickest way will be to set the X and Y of the existing cells to the new locations, and then call set data for each. We used reparenting earlier because our scenario was a series of related containers, so this may not apply to you. But bottom line - we simply move "rows" around the visible area. So creating and destroying will be slow, removing and adding to the display object list will be faster, and just moving around (x,y) will be fastest.
3) Choose what you inherit from wisely: The Flex SDK is a beast. So choose your "cells" base class wisely. For example, the SDK DataGrids, have a lightweight renderer that inherits from UITextField (Halo), as opposed to Label. Even UIComponent will be heavy in certain scenarios. Look up the asdocs for UIComponent and see if you need everything in there, else consider inheriting from further up its hierarchy.
4) Cache Calculations: Do this last in your development cycle. Once you are done with a feature, run flex profiler. Identify the longest running methods, and the most called methods. We always do this when we release, because there's always improvements to be made. There's a lot of math involved when you're developing a highly visual component, and too many calculations will slow things down.
5) Make sure you profile for memory : Unwired event listeners, rogue object references, etc will kill performance. Flex profiler is an excellent tool to combat this, so make sure you use it.
We have some good links here:
http://www.flexicious.com/resources/Ultimate/Docs/LargeDataset.htm?
Hope this helps!

If you look at any List-based control in the Flex framework, you'll see that they make significant use of item renderers which are recycled. So a DataGrid with 20 rows displayed only creates about 22 renderers and recycles them as you scroll through the list. This is why a DataGrid can hold thousands of records and still have pretty snappy performance. I recommend you check out Peter Ent's series of articles on item renderers and take a look at ListBase/List and some of the related classes to understand how to build something similar:
http://weblogs.macromedia.com/pent/archives/2008/03/itemrenderers_p.html

Without seeing your code and knowing exactly what you're trying to do...it definitely seems like you're pushing the limits of Flex by pushing that much data into the framework all at once.
Keep in mind that the Flash runtime wasn't designed to handle huge applications...but run somewhat light applications inside the browser. It also seems unlikely that your users are going to need to have access to all of those controls all at once.
You could try providing data services (Java, .NET, etc.) to drive the data in your application. You would then page through the data so that the framework is only dealing with maybe 200 - 300+ elements at a time.

In flex, if you using Mouse move event to redraw anything .. You might have experienced very slow rendering .
eg:
this.addEventListener(MouseEvent.MOUSE_MOVE, redraw);
and
public function redraw(anything:Object=null):void{
//draw something here
this.graphics.clear();
this.graphics.lineStyle(3, 0x000000);
this.graphics.moveTo(startPoint.x, startPoint.y);
this.graphics.lineTo(endPoint.x, endPoint.y);
this.scaleTextInput.x = centerPoint.x;
this.scaleTextInput.y = centerPoint.y;
}
The Above code results very slow rendering ...
Solution:
Use Event.ENTER_FRAME event instead? Although more resource intensive than the mouse move event, you should receive considerably more updates per second, allowing the mouse to appear more responsive to the user:
Eg:
this.addEventListener(Event.ENTER_FRAME, redraw); instead of
this.addEventListener(MouseEvent.MOUSE_MOVE, redraw);
and You are good to go ..Happy Flexing
More on:
http://www.deepakdhakal.com

Related

Using QtQuick Loader vs the property visible

Let's say I have a general implementation to represent a screen. The screen has a footer. The footer can have the following content:
empty or
one button on the left or
one button on the right or
one button on the left and one button on the right
I have at least 20 instances of this screen implementation within my application. I was wondering if it is better to load the buttons with a QML Loader component only if they are used within the given screen or it doesn't make that big of a difference to have the buttons always there just turn on/off their visibility?
Sidenote: each screen knows upfront how many buttons will it need if any.
It wouldn't make a lot of difference in most cases. The trade-back is CPU time vs RAM usage, hiding will save CPU time but use more memory, creating and destroying will save memory but add CPU load.
It would only begin to matter if the components are heavy and complex, which means that they will be slow to create, and use a lot of memory, in that case you have to decide based on which of the two you prefer to avoid.
Unless you already have established to have a problem with how your app performs, don't bother with premature optimizations.

Flex Spark List item render with delayed refresh

I have a spark List in which I am adding custom components manually (without an item renderer). Everything is working fine except when I add hundreds of items in the list (based on several calculations), the render time increases to several seconds.
My questions are:
Does flex automatically delay the rendition of components that are added to a list?
If not then, how can I tell the spark list to only render the components once everything is added.
I hope what I am asking makes sense. I am pretty sure the render time is increasing because I have quite a few components inside the custom component. I just need a simple answer to my questions.
One more thing to know is that,
ActionScript 3 runs on flash player based on even-driven. It means that if you run a chunk of code in blocking, anything else, including rendering, will not be executed until the code ends.
This design sometimes causes issues: If a developer adds too much job in one blocking function, the player looks frozen and unresponsive momentarily. (If the code is an infinite loop, it stops until the player detects and throws ScriptTimeoutError, or possibly forever.)
However, for your question, yes, anything will be delayed until the adding job is done. Flex components doesn't basically split the job automatically.
Flex components are rendered in the list according to the Flex lifecycle: http://help.adobe.com/en_US/flex/using/WS460ee381960520ad-2811830c121e9107ecb-7fff.html
There are two reasons your List may be running slow, your components may not be following the Flex lifecycle correctly and the second because virtual layouts are not enabled on your List.
First the hard one:
Your first step should be to ensure you are following the correct phases in your custom components for commitProperties(), measure() and updateDisplayList(unscaledWidth:Number, unscaledHeight:Number).
So long as you are not calling any method named validateNow() on either your UIComponent subclasses or the LayoutManager then your components should follow this just fine.
The second may be that your list layout is not using virtual layout. This is enabled by default in a Spark List component but if you're overriding the layout you should ensure that useVirtualLayout is set to true on whatever layout you're using.
This is the property to enable it:
http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/spark/components/List.html#useVirtualLayout
This is what it does to speed up rendering many items in a Spark DataGroup component (which a List is):
http://help.adobe.com/en_US/flex/using/WSc2368ca491e3ff92-1483ec4a12136246e76-8000.html#WS685c4ccbb85d340c6617851e121d4b8abae-8000

Need to "introspect" innards of flex <mx:itemRenderer>

I've got a flex app with a DataGrid with several columns (defined in the MXML file), and I need to "introspect" the grid columns. That is, I need to write some ActionScript code which, given the DataGrid object, can determine various things about the grid (and more specifically, the columns of the grid).
In particular, if a column is just plain text output, I don't really care about it... but if it's got "actionable" controls within it (checkboxes, linkbuttons, etc) I do.
First, I'm assuming that columns which contain "actionable" contents will be within <mx:itemRenderer> tags (else it would just be plain text); please let me know if this is incorrect.
Next I need to "dig down" into the structures, pulling the AS object corresponding to the <mx:DataGridColumn> out of the <mx:DataGrid> (I've got this), then pulling the AS object corresponding to the <mx:itemRenderer> out of the mx:DataGridColumn (two diff ways to do this; neither seems very useful), then pulling the AS object that corresponds to the <mx:Component> out of the mx:itemRenderer (if any; it's unclear to me whether the mx:Component actually creates an object), and finally pulling the AS object corresponding to the <mx:LinkButton> (or whatever) out of the mx:Component.
Does anyone know how to do this?
P.S. I understand that there's almost no limit to what could be lurking within the itemRenderer; if I can dig down that far, I'm willing to test for a handful of things that I expect and ignore the rest.
To clarify somewhat, I've been asked to provide Section 508 compliance (accessibility) to an existing application. There are a lot of pieces to this, of course, including screen readers, etc... but one of the first steps is making sure that the application can be used without a mouse.
Many of the existing screens have a UI technique consisting of a DataGrid with item renders which place controls like radio buttons and linkbuttons and whatnot into the cells (same type of control all the way down the column). All well and good, except I can find no way to interact with these controls via the keyboard.
So, I modified one screen to have a hot key which pops up a context menu, allowing the user to arrow up/down among the actionable items, and press ENTER to choose one (toggle the checkbox, press the linkbutton, etc). But this was screen-specific, and it will be too easy for someone to update the screen (e.g. adding another actionable column) and neglect the menu.
A better (?) approach was suggested: subclass the data grid, introspect to find the actionable columns, build the menu automatically, and now all we have to do is swap out the SuperDataGrid for the DataGrid, and our screens will be 508 compliant.
If someone can recommend a better way to make the screens 508-compliant (without redesigning the UI) and with minimal per-screen effort, I'm all ears.
Maybe I'm not being clear enough, since you keep missing the point, so let me try again.
I'm NOT writing application-level code... if I were, I'd know exactly what the logic is doing and I'd be able to use the bound data in the normal way. In fact, the application-level code DOES use the bound data in the normal way. But that's totally beside the point.
What I'm TRYING to do is write "infrastructure-level" code: that is, code which runs "below" the level of the application logic. I'm trying to effectively add a feature to DataGrids which Adobe should have included, but didn't. If I can get this class working, it will be possible to just drop it into dozens of screens WITHOUT ME, AS THE CLASS AUTHOR, KNOWING ANYTHING ABOUT THOSE SCREENS OR THE LOGIC WITHIN THEM. The only way I can imagine this working is to look into the datagrid and discover, at run time, what types of controls lurk within it, and possibly what they're bound to (actually, I can probably just execute whatever the click="foo()" attribute says to do, and I won't need to know what they're bound to).
Does this make sense?
Is it possible?
Item renders interact with the outside world through their data property. They should render the data as desired and make changes to data as required. They should not reach outside and you should not try to reach in to affect an item renderer directly.
As far as the underlying problem you're trying to solve, you haven't stated it at all. You're describing a desire to follow through on a particular solution only but haven't described the underlying problem. What are you really trying to accomplish? Don't talk about getting access to item renders or digging into the DataGrid, but what interaction or affect on the rows do you want? The problem is your approach is somewhat backwards and that's why it's not working out.

Can I suspend drawing to perform multiple successive updates in Flex?

I've written a simple calendar control to allow for selecting single days, weeks, months and so on. The simplicity comes from the fact that I don't really do any drawing myself, opting instead to create a bunch of boxes and labels to act as date cells for the calendar.
When a date or a date range is selected, I need to highlight that range. It's easily done by iterating through the cells and switching their style. [edit:] However, this seems to cause a delay during which the cells are first drawn as if the style name was blank, and then re-drawn with the correct style, despite the fact that I never explicitly set the style to null -- I alternate between "CalendarCell" and "CalendarCellSelected".
If this were Windows Forms, I'd call SuspendLayout on the parent container to make sure the controls are repainted only after I've finished the updates. What I'm looking to know is whether or not a similar solution exists for Flex. I'd like to avoid drawing the entire calendar "manually", so to speak, if that's at all possible.
edit: changed the problem description to more accurately reflect what I'm seeing.
Are you using callLater() at all?
If you use callLater() it may impove your visuals as it batches up changes until it needs to draw a frame or you force a frame draw with validateNow() or similar. It might be enough in your case.
Is your calendar control a UIComponent? Is it using the standard invalidation methods like commitProperties(), updateDisplayList(), etc?
What you might want to do is keep a private array of the cells that will have their styles changed, but then do the actual style switching in your commitProperties() override. I'm just not sure if setStyle() fires an validateNow() because the flickering is a bit surprising.
This may not be exactly what you're looking for, but David Coletta at Adobe has posted a video explaining an EventCoalescer that they use in Buzzword for deferring events that update specific areas of the app UI until the user has stopped moving the insertion point in the text, for example.
This blog post by Hans Van de Velde also has a similar solution, and actual code for it as well.

Flex Post Event Screen Updates

I came across this topic today while investigating something very strange. Doing certain things in our Flex app can cause the number of frames rendered to rocket, from 12fps to ~30fps: loaded animations start playing at high speed and the GUI starts to lock up.
Since everything I've read on Flex/Flash hammers home the point "the frame rate is capped at the fps set in the top level app", it seems the only way these extra renders can be happening is due to some events causing them (no programmatic changes to the stage's framerate are done anywhere). Since it only happens when I put my update logic in the ENTER_FRAME handler, I'm trying to figure out what might be happening which to apparently causing Flex to go render-crazy.
Hypothesis: something in my update function is triggering an immediate screen update, this raises another ENTER_FRAME immediately, which means my update loop gets called, which triggers another immediate screen update, ...
We have Flex components used in our GUI, if this is a factor. I don't really know where to go next on this.
Clarifications:
When I say things speed up, there
are two ways this manifests.
Firstly, my ENTER_FRAME handler gets
called far more often.
Secondly, a
loaded Flash SWF with a looping
animation built in suddenly speeds
up to te point it looks silly.
I am not using updateAfterEvent, I only
found this existed when researching
this problem. Apparently, some
events on Sprite subclasses
automatically call this and I wonder
if that's the root cause.
I am not doing any direct messsing about with rendering at all. Background animations play automatically as they have timelines built-in from CS3 authoring, all our update function does is change the position of DisPlayObjects or add/remove them etc
Update:
I added a label to my app to print out stage.frameRate, and discovered at certain times, it suddenly changes from 12 to 1000 (the maximum allowed value). While it was trivial to add a line to my ENTER_FRAME handler to reset it that's hardly a big help.
Also, even doing this, the rendering is all messed up. Certain actions (like raising an Alert popup) make it all spring back into life.
Unfortunately, I am not able to view the source of the Stage class to set a breakpoint on the setter property.
That's very interesting about the Flex loading 'set to 1000fps' thing. What we have are several Flex applications which all provide a common interface. A master app is in charge of loading these modules as required through the SWFLoader class. However, the loading process already takes into account the delayed loading... when the SWF loads we then wait for the APPLICATION_COMPLETE from the SystemManager. Once this is received, shouldn't the applications completion have occurred?
Flex sets the frame rate to 1000 during "phased instantiation" of Flex components, which occurs only during initial load of a flex swf. This allows it to build all components very quickly.
Are you waiting for the Flex app to be fully loaded and constructed? You should be waiting for FlexEvent.CREATION_COMPLETE before working with your Flex content.
If you would like a reference to where this occcurs, look in the Flex LayoutManager class, line 326 (using Flex SDK 3.0.194161), in the setter for the property usePhasedInstantiation.
Update:
APPLICATION_COMPLETE should have you covered for the initial load.
This actually happens any time components are created directly from MXML. So there are a few other cases to look for. Are you using any Repeaters? Do you use any navigation containers that are building their children on demand?
One thing I'm not clear on - are you seeing that the actual screen refreshes are occurring faster than the published framerate? Or is it that your animations are moving faster but the screen refreshes are unchanged? (i.e., it used to move 10 pixels per second, but now it moves faster than that, regardless of how often the screen is drawn.)
An easy way to check this would be to try publishing your content at 1 fps. It should be clear whether the screen is redrawing once per second, but animated elements are being moved more frequently than that, or whether the screen is actually updating more frequently.
If the latter, are you using any updateAfterEvent() methods in your code? This can cause actual screen refreshes to occur faster than the published framerate. It shouldn't affect ENTER_FRAME events though. You should still only get one of those per frame update.
Alternately, are the things you're animating just Sprites and so on, or are you implementing them as Flex components, and trying to redraw them with invalidate() methods and RENDER events and so on?
If you could clarify a few of these points in the question the answer might be clearer. Thanks...
Thanks for the clarifications. If a loaded clip with a animation (I assume you mean a frame animation) is speeding up, then that certainly sounds like something is changing your playback framerate, as opposed to other things that could be going on. With that said it's not a problem I've seen crop up before, but I do think there are some things you could try that ought to narrow down where the problem is:
You might as well try tracing out stage.frameRate during the speed-up. Presumably nothing ought to be changing your framerate, but since that would explain your issues you might as well rule it out.
Try removing as many GUI components as possible and seeing if the problem still occurs, if it's possible to trigger the problem without them.
One sanity check you could try, if it's feasible, is to copy some of the contents of your game into a fresh project and try it there. Sometimes mysterious issues like this happen because some class or SWC is being imported somewhere that everyone forgot about.
You could try driving your code from a different event. For example, as far as I know driving it from Event.EXIT_FRAME or Event.FRAME_CONSTRUCTED ought to look the same, but if it doesn't then that's a hint. Alternately, you could try driving it from something like a keyboard event or MouseEvent.MOUSE_MOVE. Then if updates occur even though you're not firing events, you'll know something else is driving things besides your event loop.
Those are the things I'd try, anyway. Hope you track it down...

Resources