tags:

views:

155

answers:

2

In an AIR application I have the following code:

theDialog = PopUpManager.createPopUp( this, TheDialogClass, true ) as TheDialogClass; theDialog.addEventListener(FlexEvent.CREATION_COMPLETE, cpuIntensiveCalc);

At the end of cpuIntensiveCalc the dialog is removed. The dialog informs the user that "something is going on, please stand by."

The problem is that cpuIntensiveCalc starts before the dialog draws. So the user experience is that the application freezes for 10 seconds with no indicator, then the modal dialog flashes quickly (less than a second) on screen.

The Adobe docs say this about creation_complete

Dispatched when the component has finished its construction, property processing, measuring, layout, and drawing.

So this feels like the correct event.
In the name of completeness, I also tried

theDialog = PopUpManager.createPopUp( this, TheDialogClass, true ) as TheDialogClass; cpuIntensiveCalc();

But had the same results.

TIA

+1  A: 

The reason for this is that the Flash Player is single threaded, and so you are blocking the UI from reacting to the Dialog Popup until the maths chunk is finished.

Hacky fix time...

You have two options.

(This one should work, but is untested) Wrap the cpuIntensiveCalc() call in a callLater, so that the UI can finish rendering before you block the rendering.

Or

Use "Green Threads" to break up your processing so that you don't completely block the UI processing. Take a look.

Gregor Kiddie
Yeah, I tried callLater, no dice. :| I also tried to introduce a delay using a Timer. So I create the popup, then start the timer with a TimerEvent.TIMER listener. This is SUPER hacky, but I just wanted to see it work. To make it work I had to have the delay pretty high, like 250ms.
PaulC
The second solution is the less hacky and probably best solution for a single-threaded system like AS3 anyway. You can also try the Active Object pattern, and break up your computation into smaller tasks. http://en.wikipedia.org/wiki/Active_object
Glenn
A: 

Use enterFrame event on popup. Don't forget to remove the listener in the enterFrame event handler - otherwise the cpu intensive method will be called in each frame, crashing your app. If this doesn't work at first, use a private number as a counter and keep incrementing it in the enter frame handler - call cpu heavy method only when the counter reaches the appropriate value. Find the 'appropriate' value by trail and error.

theDialog = PopUpManager.createPopUp(this, TheDialogClass, true) as TheDialogClass;
theDialog.addEventListener(Event.ENTER_FRAME, onEnterFrame);
private function onEnterFrame(e:Event):void
{
  //can use theDialog instead of e.currentTarget here.
  (e.currentTarget).removeEventListener(Event.ENTER_FRAME, onEnterFrame);
  cpuIntensiveCalc();
}
//in case the above method doesn't work, do it the following way:
theDialog.addEventListener(Event.ENTER_FRAME, onEnterFrame);
private var _frameCounter:Number = 0;
private function onEnterFrame(e:Event):void
{
  _frameCounter++;
  var desiredCount:Number = 1;//start with one - increment until it works.
  if(_frameCounter < desiredCount)
    return;
  //can use theDialog instead of e.currentTarget here.
  (e.currentTarget).removeEventListener(Event.ENTER_FRAME, onEnterFrame);
  cpuIntensiveCalc();
}
Amarghosh