/* This is a basic example of how to work with the LIBSPARK THREAD LIBRARY In this example first a twitter api call is done and all the avatar images of this call are beeing arranged. Then the user will be asked to click at the stage as an example for event handling and timeout processing. Finally a custom process will be triggered that does some heavy math calculation which should take considerable amount of time on all common computers. The loading of the images is parallel, all errors that can occur while loading will be displayed as small text field. have fun! The library is cool shit! Ps.: This is utilizing the ThreadStepProcessor extension for the Thread library. */ package { import org.libspark.thread.*; import flash.display.*; public class ThreadLibraryExample extends Sprite { public function ThreadLibraryExample(){ // Tell the Thread framework to use a EnterFrame // implementation of Executor for Pseudothreads Thread.initialize( new EnterFrameThreadExecutor() ); // Create a startup thread and start it // -> I pass in this thread of var setup: SetupThread = new SetupThread( this ); setup.start(); } } } import flash.utils.getQualifiedClassName; import org.libspark.thread.Thread; import org.libspark.thread.step.StepThread; import org.libspark.thread.threads.display.LoaderThread; import org.libspark.thread.threads.net.URLLoaderThread; import org.libspark.thread.utils.Progress; import org.libspark.thread.utils.IProgress; import org.libspark.thread.utils.events.ProgressEvent; import org.libspark.thread.utils.ParallelExecutor; import org.libspark.thread.utils.IProgressNotifier; import flash.net.navigateToURL; import flash.display.*; import flash.errors.IOError; import flash.events.Event; import flash.net.URLRequest; import flash.text.*; import flash.system.Security; // The Setup Thread has to extend Thread in order to do Thread // That is a bit annoying tbh. import flash.events.MouseEvent; class SetupThread extends Thread { private var _container: DisplayObjectContainer; private var _configLoader: URLLoaderThread; private var _allImagesLoader: ParallelExecutor; private var _messageDisplay: MessageDisplay; private var _pseudoThread: PseudoThread; public function SetupThread( container: DisplayObjectContainer ) { _container = container; } // Overriding the "run" template method of the Thread class // Other events like "start" will be triggered properly // around that override protected function run(): void { // Create a URLLoaderThread for the twitterfeed that offers the images _configLoader = new URLLoaderThread( new URLRequest("http://search.twitter.com/search.atom?q=thread") ); // Configloader is started! _configLoader.start(); // Let _configLoader block the current thread // _configLoader is now a subthread _configLoader.join(); // register error handlers, for both errors that occur error( IOError, handleError ); error( SecurityError, handleError ); // After the configuration is loaded, load the images that are specified in it next( loadImagesOfTwitterFeed ); } // If a error occurs, show a error message! private function handleError( error: Error, thread: Thread ): void { message( error.message, true ); // Interrupt eventually started subthreads and stop loading following interrupt(); } private function loadImagesOfTwitterFeed(): void { // If a error occured, now the thread would be interrupted! if( !isInterrupted ) { var xml: XML = new XML( _configLoader.loader.data ); var images: XMLList = xml..(xml.namespace())::link.(@type == "image/png" || @type == "image/jpeg" || @type == "image/jpg" || @type == "image/gif" ); // Create a new ParallelExecutor that loads the images // beside each other _allImagesLoader = new ParallelExecutor(); // Add all images of the xml as LoaderThread to the loader for each( var image: XML in images ) { _allImagesLoader.addThread( new LoaderThread( new URLRequest(image.@href) ) ); } // Start the loading of all images _allImagesLoader.start(); // Set this again as subthread in order to wait for the images // to be loaded _allImagesLoader.join(); // The error handlers from before got removed // To listen again to the events added once more error( IOError, handleError ); error( SecurityError, handleError ); // Next call would be to add the images to the stage next( addImages ); } } private function addImages(): void { // Could have been interrupted in last step! if( !isInterrupted ) { // Just for demo reasons: Draw all images var stageWidth: int = _container.stage.stageWidth; var maxHeight: int = 0; var x: int = 0; var y: int = 0; for( var i: int = 0; i< _allImagesLoader.numThreads; ++i ) { // Pulling the data from LoaderThread var content: DisplayObject = LoaderThread(_allImagesLoader.getThreadAt(i)).loader; if( x + content.width > stageWidth ) { x = 0; y += maxHeight; } content.x = x; content.y = y; if( content.height > maxHeight ) { maxHeight = content.height; } x += content.width; _container.addChild( content ); } // Example for event handling // Message is displayed message( "click me in the next 5 seconds" ); // And once a event occurs -> The next process is triggered event( _container.stage, MouseEvent.MOUSE_DOWN, startPseudoThread ); // Unless you clicked in 5 seconds ( 5000 ms ) wait( 5000 ); // Tell the Thread system that it should show a message // once the timeout for wait has been exceeded timeout( showClickFailed ); } } private function showClickFailed(): void { // Wait triggered this timeout! message( "You were too slow!", true ); } private function startPseudoThread( event: Event = null ): void { message( "Starting pseudo thread" ); // Initializing a pseudo thread as before _pseudoThread = new PseudoThread(); // and starting it _pseudoThread.start(); // waiting for it... _pseudoThread.join(); // ... and displaying the progress _pseudoThread.progress.addEventListener( ProgressEvent.UPDATE, showPercentage ); error( Error, handleError ); next( finish ); } private function showPercentage( event: ProgressEvent ): void { // Percentage is stored in Progress class from 0 to 1 message( int( _pseudoThread.progress.percent * 100) + "%" ); } private function finish(): void { // Wippa - the pseudo thread finished its calcuation message( "pseudo thread finished" ); } override protected function finalize(): void { // Removing the references, for more controlled // garbage cleaning after everything is done _container = null; _configLoader = null; _allImagesLoader = null; _messageDisplay = null; } internal function message( message: String, error: Boolean = false ): void { if( _messageDisplay ) { _container.removeChild( _messageDisplay ); _messageDisplay = null; } if( message ) { _container.addChild( _messageDisplay = new MessageDisplay( message, error ) ); } } } // Pseudo thread that counts up to the MAX constant (nothing spectacular) class PseudoThread extends StepThread implements IProgressNotifier { // amount to count up to private static const MAX: int = 50000000; private var _progress: Progress = new Progress(); private var _i: int; override protected function init(): void { // initial state definition _progress.start( MAX ); _i = 0; } override protected function process(): Boolean { ++_i; // return true if its completly executed return _i >= MAX; } override protected function updateState(): void { // fill the current state into progress bar _progress.progress( _i ); } // Implementation of IProgressNotifier method // for the progress bar. public function get progress(): IProgress { return _progress; } } // Just a display to show a occured error class MessageDisplay extends Sprite { private var _text: TextField; public function MessageDisplay( message: String, error: Boolean ) { addChild( _text = new TextField() ); _text.defaultTextFormat = new TextFormat( "Verdana", 10, 0xFFFFFF ); _text.autoSize = TextFieldAutoSize.LEFT; _text.text = message; with( graphics ) { beginFill( error ? 0xAC0000 : 0x00AC00 ); drawRoundRect( 0, 0, _text.textWidth+10, _text.textHeight+10, 5 ); endFill(); } addEventListener( Event.ADDED_TO_STAGE, render ); } private function render( event: Event ): void { x = stage.stageWidth/2 - width/2; y = stage.stageHeight/2 - height/2; } } Libspark Threading example, english - including ThreadStepProcessor