Sometimes, fl.core.UIComponent redraws too often

Recently, as I was working on a Flash component (not a Flex component, mind you), I found myself wondering why the component would redraw for supposedly no reason. It had obviously drawn itself to display the current state after a property change, but sometimes it would throw in one extra redraw a bit later. If you’re unfamiliar with the way the “fl” components work, they use a system of invalidation where property changes will queue up a drawing cycle for later (typically before the next frame is drawn by Flash Player’s renderer). When the extra redraw slipped in there, it seemed that something wasn’t getting cleaned up properly during the validation cycle.

When you create an “fl” component that has children that are also “fl” components, you’re required to call a function named drawNow() on the sub-components inside the parent’s draw() function. You want to do this because many users will find it aesthetically undesirable to see those sub-components update one frame later rather than immediately. In fact, the architecture actually forces you to call drawNow() because it refuses to queue another redraw while in the “call later phase”. Of course, there are ways to force “fl” sub-components to invalidate during that call later phase if you don’t mind patching the source yourself, but that’s a different story.

Call later, or else!

That’s the background for how the architecture works. Here’s the problem I discovered. When you set a property of a sub-component from outside its parent, that sub-component will invalidate and callLater() will get it ready for a redraw. If, for some reason, the parent redraws before its sub-component, the sub-component will draw when drawNow() is called, but the redraw it independently queued up earlier won’t be removed from the queue!

The only time that the draw() function gets removed from the queue is when the callLaterDispatcher() receives the stage’s render event. Instead, UIComponent should account for the possibility that a certain functions that will be “called later” may not need to be called again if they get called early. Here’s a patch to fl.core.UIComponent that will do just that for component drawing:

protected function validate():void
{
	invalidHash = {};

	//remove draw() from the "call later" queue
	delete this.callLaterMethods[draw];
}

I simply added one line at the end of the function validate() This function gets called at the end of draw(). The default version only cleans the invalidation hash, which tracks changes to minimize the number of component parts that need to redraw. My addition also ensures that it only redraws once. If the component has validated, then there’s nothing invalid to require another draw.

It’s worth noting that an extra redraw isn’t the end of the world. For most components, it won’t cause any noticeable problems, but for some, it may impact performance. Things like the layout containers in Yahoo! Astra are a bit more CPU-intensive than most “fl” components because they need to determine ideal dimensions, the best positioning of components, and whether scrollbars are needed and that involves some nasty looping. They have a few flags to indicate whether certain changes affect the layout at all, but still, that’s not always perfect and drawing the component again for no good reason isn’t useful.

By the way, if you ever want to monkey patch a component in a specific Flash or Flex project, it’s easy.

  1. Copy the original source file into a new file. Make sure the package structure is the same as the original.

  2. Make any changes that are needed.

  3. Add the folder for the top-level package of the new component to your compiler’s “source path”. Make sure your patched source is higher in the list than the original version so that the compiler knows that it is more important. Typically, if the patched version is in the project’s own directory, it will be given more importance.

Enjoy!

About Josh Tynjala

Josh Tynjala is a frontend developer, open source contributor, bowler hat enthusiast, and karaoke addict. You might be familiar with his project, Feathers UI, an open source user interface library for Starling Framework that is included in the Adobe Gaming SDK.