Adobe Flash player的运行时环境不能支持多线程,除了非常特殊的扩展操作。Flash player使用了古老的逐帧式单线程独立执行模式。这就意味着在绘制ui和处理用户交互的时候会直接阻塞数据处理或其他重量级操作。flex框架的ui实现了一个标准的无效更新模式这样可以减轻大量ui重绘对组件的影响。ui组件还具有一个calllater方法,但是没有相应的后端数据处理。
Thread.as类在flex项目中可以被任何一个flex类使用作为一个线程工作。简单的创建一个worker方法做一个单一的计数工作,它通常是在一个等待的工作队列中使用。然后创建一个Thread类的实例提供给worker作为第一个参数。记得保证worker线程是非常轻量级的,做的事情越少越好。workder方法会被重复的调用,直到返回值为true,说明工作已经完成。对于这个类的使用逻辑需要注意的一点是,要清楚什么时候调用worker方法能不阻碍flash player的运行。这样才能让后台处理数据,而用户依然可以与ui交互。
你可以提供一个work完成的方法。这样可以在工作结束后调用这个方法。
在实际应用中还要考虑多个线程并行执行的问题。注意分配给每个线程的执行时间。但是如果你有很多个线程或者是一个workder方法需要大量的执行时间的情况下你仍有可能消耗完所有的资源。
运行例子
源代码
转载:http://bbs.9ria.com/thread-73420-1-1.html
Thread.as
package com.dreamingwell.util
{
import flash.events.Event;
import flash.events.EventDispatcher;
import flash.system.System;
import flash.utils.setTimeout;
import mx.core.FlexGlobals;
import mx.core.UIComponent;
import mx.managers.SystemManager;
import mx.rpc.IResponder;
dynamic public class Thread extends EventDispatcher
{
/* Statics */
/** Event type dispatched when the thread completes its work */
public static const THREAD_COMPLETE_EVENT:String = "threadCompleteEvent";
/** Event type dispatched when the thread will begin work in the next frame */
public static const THREAD_STARTING_EVENT:String = "threadStartingEvent";
/** Event type dispatched when the thread has manually stopped */
public static const THREAD_STOPPED_EVENT:String = "threadStoppedEvent";
/** The calculated time in ms that each frame is allowed; from Flash Player's framesPerSecond */
private static var timePerFrame:Number = -1;
/** The percent, as a number between 0 - 100, of time alloted in each frame to all thread's executions */
public static var percentThreadExecutionTimePerFrame:Number = 50;
/** The currently running number of threads */
protected static var numberOfActiveThreads:Number = 0;
/* Local Data References */
private var _inProgress:Boolean = false;
private var token:Object;
private var workFunction:Function;
private var completeFunction:Function;
/** Determines whether this thread is currently in progress */
public function get inProgress():Boolean {
return _inProgress;
}
/**
* This is class is used to create a "thread" of work. Supply a "work" function, that performs a tiny amount
* of work, and returns a boolean as to whether the thread is complete. The "complete" function will be called when the
* work function returns that it has completed.
* <Br><Br>
* This thread object is the only argument passed to the work and complete functions. Thread is a dynamic object,
* so you can add any property to it you like. For example, you can do the following:
* <Br><Br>
* var workerThread:Thread = new Thread(workerFunction);
* <br>workerThread.token = myTokenObject;
* <br>workerThread.someRandomId = idObject;
* <Br>
* <br>private function workerFunction(thread:Thread):Boolean {
* <Br>
* <br> var workQueueCompleted:Boolean = false;
* <Br>....
* <Br>
*
*
*
* return workQueueCompleted;
* }
*
*
* @workFunction The function that will be called repeatedly. Keep the execution time of this function to
* an absolute minimum. It should take one argument, which will be this thread instance. Thread is a dynamic
* class, so you can manually add any property you'd like to be used in the worker function. The worker function
* should return "true" when all available work has been completed; thus ending the execution of this thread.
*
* @completeFunction The function that will be called once the worker thread has completed.
*
* @autoStart A boolean flag as to whether the thread should start in the immediately following frame. If you set this false
* you must manually call the start() method.
*
*
* */
public function Thread(workFunction:Function, completeFunction:Function = null, autoStart:Boolean = true)
{
/* Store given token */
this.token = token;
this.workFunction = workFunction;
this.completeFunction = completeFunction;
/* Setup the time allowed per execution period */
if(timePerFrame == -1) {
timePerFrame = 1000 / (FlexGlobals.topLevelApplication as UIComponent).stage.frameRate;
}
/* Auto start */
if(autoStart)
start();
}
/** Starts this thread's execution, only if it is not already in progress. */
public function start():void {
if(_inProgress)
return;
_inProgress = true;
/* Increment the active threads */
numberOfActiveThreads++;
/* Dispatch a starting event */
dispatchEvent(new Event(THREAD_STARTING_EVENT));
setTimeout(doWork,1);
}
/** Ends this thread's execution prematurely; only if this thread is in progress. */
public function stop():void {
if(!_inProgress)
return;
_inProgress = false;
/* Decrement the number of active threads */
numberOfActiveThreads--;
/* Dispatch an event to say this thread will no longer be doing work */
dispatchEvent( new Event(THREAD_STOPPED_EVENT));
}
/** Performs each unit of work, by calculating the available remaining time, and calling
* the worker function. */
protected function doWork():void {
/* get the start time */
var startTime:Date = new Date();
var currentTime:Date = new Date();
/* A first loop, to allow at least one work block to go through per frame, in case too many threads
are running */
var firstLoop:Boolean = true;
/* Calculate the time alloted for this threads execution in this frame */
var timePerFrame:Number = (Thread.timePerFrame * (percentThreadExecutionTimePerFrame / 100) ) / numberOfActiveThreads;
/* loop until alloted time has lapsed, allow at least one loop */
while( _inProgress &&
(startTime.time + timePerFrame > currentTime.time || firstLoop)) {
firstLoop = false;
/* Do the work function, and then evaluate whether it's complete */
if(workFunction(this)) {
/* Tell this not to */
_inProgress = false;
/* Decrement the number of active threads */
numberOfActiveThreads--;
/* Do complete work */
threadComplete();
break;
}
/* Update to the new time */
currentTime = new Date();
}
if(_inProgress)
setTimeout(doWork,1);
}
/** Calls the completeFunction and dispatches the complete event */
protected function threadComplete():void {
if(completeFunction != null)
completeFunction(this);
dispatchEvent(new Event(THREAD_COMPLETE_EVENT));
}
}
}
ThreadExamples.mxml
<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx" minWidth="955" minHeight="600" viewSourceURL="srcview/index.html">
<fx:Script>
<![CDATA[
import com.dreamingwell.util.Thread;
import mx.controls.Alert;
/* Queue of objects on which to work */
private var workQueue:Array = new Array();
/* Number of iterations of work to do */
[Bindable] private var iterations:Number = 10000;
/* Number of iterations completed */
[Bindable] private var iterationsCompleted:Number = 0;
/* Flag to state when we're working, to disable buttons. */
[Bindable] private var inProgress:Boolean = false;
protected function threadedButton_clickHandler(event:MouseEvent):void
{
/* Reset the iteration count */
iterationsCompleted = 0;
/* Set this as in progress */
inProgress = true;
var thread:Thread = new Thread(threadedWorker,threadComplete);
thread.someRandomPropertyName = new Object(); // you can set any property you like on the thread; its dynamic
}
protected function singleThreadButton_clickHandler(event:MouseEvent):void
{
/* Reset the iteration count */
iterationsCompleted = 0;
/* Call the same threaded worker function that does a small amount of work
but without using the thread class. Will interupt the UI, and make UI seem frozen */
for(var i:Number = 0; i < iterations; i++) {
threadedWorker(null);
}
threadComplete(null);
}
protected function threadedWorker(thread:Thread):Boolean {
/* doing our heavy lifting here.
Notice that you can change this number to any value large or small, and the UI remains responsive.*/
for(var count:Number = 0; count < 100000; count++) {
}
/* Now increment the iterations completed count */
iterationsCompleted++;
/* Now update the progress bar, which will actually only visibly update
after this frame has exited. */
progressBar.setProgress( iterationsCompleted , iterations);
/* If this is a threaded instance, check the iteration count and return */
if(thread != null)
return iterationsCompleted == iterations;
/* This is not a threaded instance, just return false, doesn't matter */
return false;
}
protected function threadComplete(thread:Thread):void {
/* Turn off in progress */
inProgress = false;
Alert.show("Completed " + iterations + " iterations!");
}
]]>
</fx:Script>
<fx:Declarations>
<!-- Place non-visual elements (e.g., services, value objects) here -->
</fx:Declarations>
<s:layout>
<s:VerticalLayout/>
</s:layout>
<s:Label>
1) Click the "Perform Threaded Work" button. Notice that the progress bar updates, and the browser does not freeze.
</s:Label>
<s:Label>
2) Click the "Perform Non-Threaded Work". Notice that the entire flash player freezes, possibly including the browser. The progress bar does not update. Wait until execution completes.
</s:Label>
<s:Label>
3) Right click to view source.
</s:Label>
<s:HGroup>
<s:Button id="threadedButton" label="Perform Threaded Work" click="threadedButton_clickHandler(event)" enabled="{!inProgress}" />
<s:Button id="singleThreadButton" label="Perform Non-Threaded Work" click="singleThreadButton_clickHandler(event)" enabled="{!inProgress}"/>
</s:HGroup>
<mx:ProgressBar id="progressBar" indeterminate="false" mode="manual" maximum="{iterations}" minimum="0" />
</s:Application>
252

被折叠的 条评论
为什么被折叠?



