views:

293

answers:

1

I've got a Flash UI that does a periodic server call to get some updated information. The call uses the flex sdk's rpc.soap.Operation class. It looks something like this:

var wsOperation:Operation = Operation(webService.getOperation(SomeOperation));              
wsOperation.addEventListener("fault", wsError);
wsOperation.addEventListener("result", wsResult);           
wsOperation.send(...some params);

This call gets some data from a SQL database. I have timed the call from right before the send to the start of the wsResult function at ~4 seconds. During this time, my UI is not updated. It is frozen/unresponsive.

Now, I know Flash is single-threaded/asynchronous, so I'm not sure why this is happening. I see that the send(..) function returns an AsyncToken which I am not using. Could this have something to do with it?

Any other ideas as to why this is happening are appreciated. Thanks.


I still haven't found an acceptable solution to this. It seems ridiculous that I would have to Pseudo thread to get flash to update the UI during a 4 second call. I'm wondering if maybe the parsing of the soap response could be taking up a lot of time. If there is a lot of processing to do, will Flash delay updating the UI indefinitely?

+3  A: 

You will get a UI freeze in Flash because it is single threaded. However, you can do pseudo threading with something like this:

package
{
 import flash.display.DisplayObjectContainer;
 import flash.events.Event;
 import flash.events.EventDispatcher;
 import flash.events.KeyboardEvent;
 import flash.events.MouseEvent;
 import flash.utils.getTimer;
 import mx.core.UIComponent;
 import mx.managers.ISystemManager;

 public class PseudoThread extends EventDispatcher
 {
     public function PseudoThread(sm:ISystemManager, threadFunction:Function, threadObject:Object)
     {
         fn = threadFunction;
         obj = threadObject;

         // add high priority listener for ENTER_FRAME
         sm.stage.addEventListener(Event.ENTER_FRAME, enterFrameHandler, false, 100);
         sm.stage.addEventListener(MouseEvent.MOUSE_MOVE, mouseMoveHandler);
         sm.stage.addEventListener(KeyboardEvent.KEY_DOWN, keyDownHandler);

         thread = new UIComponent();
         sm.addChild(thread);
         thread.addEventListener(Event.RENDER, renderHandler);
     }

     // number of milliseconds we think it takes to render the screen
     public var RENDER_DEDUCTION:int = 10;

     private var fn:Function;
     private var obj:Object;
     private var thread:UIComponent;
     private var start:Number;
     private var due:Number;

     private var mouseEvent:Boolean;
     private var keyEvent:Boolean;

     private function enterFrameHandler(event:Event):void
     {
        start = getTimer();
        var fr:Number = Math.floor(1000 / thread.systemManager.stage.frameRate);
        due = start + fr;

        thread.systemManager.stage.invalidate();
        thread.graphics.clear();
        thread.graphics.moveTo(0, 0);
        thread.graphics.lineTo(0, 0);   
     }

     private function renderHandler(event:Event):void
     {
         if (mouseEvent || keyEvent)
             due -= RENDER_DEDUCTION;

         while (getTimer() < due)
         {
            if (!fn(obj))
            {
                if (!thread.parent)
                    return;

                var sm:ISystemManager = thread.systemManager;
                sm.stage.removeEventListener(Event.ENTER_FRAME, enterFrameHandler);
                sm.stage.removeEventListener(MouseEvent.MOUSE_MOVE, mouseMoveHandler);
                sm.stage.removeEventListener(KeyboardEvent.KEY_DOWN, keyDownHandler);
                sm.removeChild(thread);
                thread.removeEventListener(Event.RENDER, renderHandler);
                dispatchEvent(new Event("threadComplete"));
            }
         }

         mouseEvent = false;
         keyEvent = false;
     }

     private function mouseMoveHandler(event:Event):void
     {
        mouseEvent = true;
     }

     private function keyDownHandler(event:Event):void
     {
        keyEvent = true;
     }
 } 
}

This will enable you to do a process without the UI Freeze. It basically uses the stage's RENDER event to defer processing. This code performs as much Actionscript computation as possible limited by the time needed to maintain the frame rate. For more information see: http://blogs.adobe.com/aharui/2008/01/threads_in_actionscript_3.html

Todd Moses
Thanks for the idea. I'm going to look into this. However, since it is asynchronous, shouldn't flash send the request, and then go back to processing UI stuff until it is interrupted with the returning data? Why is it necessary to do this pseudo threading?
SP
It mimics two processes working at once. The send request and then process UI is your problem now with the freeze. Using something like the same I gave you will eliminate screen freeze in just about all circumstances - giving your user a better experience.
Todd Moses
I don't see how this could fix the problem, considering he's dealing with with stuff that is already async. Might just be a bug in the player using. Or maybe the call to send is not the problem at all, you're sure that's where it hangs?
sharvey
Its a common solution to a common Flash problem. While there could be other causes the usual cause is a process taking a long time to complete which freezes the UI.
Todd Moses