The Flash Player has only limited thread ( example: request from server with async, event handling, video rendering ), but how can we delegate (or emulate) a Thread? (Not) Simply :) If you run a huge while or for each, you experienced that the UI froze.... Because the Flash Player has frames (and frame times too), so if your code don't fit in a frame time, the Flash can't update the UI.
The solution is: Use PseudoThread, and slice your function to. What is function slicing? If your program do A->B->C->D->E you can split "virtually" 5 segment. If you know, what is the actual segment that need to run, and rebuild the function state ( the variables that use common each segment ), you can pass the A, and some frametime later you can pass the B segment and so on.
protected function button2_clickHandler( event : MouseEvent ) : void {
var thread :
PseudoThread
= new PseudoThread( systemManager, primeGen, { 'from' : 0, 'to' : 10000 } );
thread.addEventListener( "threadComplete", threadCompleteHandler );
}
protected function primeGen(obj:Object):Boolean {
var divs : Number = 0;
var fromPrime : Number = 2;
if ( obj.currentPrime == null ) {
obj.currentPrime = Number( obj.from );
}
var i : Number = Number( obj.currentPrime );
divs = 0;
for ( var j : Number = 1; j <= i; j++ ) {
if ( i % j == 0 ) { divs++; }
if ( divs > 2 ) break;
}
if ( divs == 2 ) {
primes.text += i.toString() + "\n";
}
obj.currentPrime++;
return ( obj.currentPrime < obj.to );
}
protected function threadCompleteHandler( event : Event ) : void {
trace( 'finished' );
}
What are we doing? Simple: pass an object ( with from and to in this example ), and each frametime we calculate only one prime. There is a currentPrime value that tell us, what is the number that we will test ( increment the value each time ), and the function return value always TRUE ( in the end, the return value will be FALSE ).
How can we slice other program codes? If you split your code to segment ( code blocks ), and pass the value currentSegment=1..5... and the program check the currentSegment with a switch() case ( the shared values need to save! ). That's all, until the Flash Player 12 released. :)
Note: The primeGen function is not the worst algoritms to test the number, only demonstrate it slow function not froze the whole application. ( you can optimize the function to check the div only the sqrt of the actual number).
The PseusoThread code is:
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, 0);
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;
}
}
}
No comments:
Post a Comment