包 | flash.system |
类 | public final class Worker |
继承 | Worker EventDispatcher Object |
语言版本: | ActionScript 3.0 |
运行时版本: | Flash Player 11.4, AIR 3.4 |
worker 允许您在另一个 worker(包括主 swf 的 worker)正在运行其他操作的同时“在后台”执行代码。在非 worker 上下文中,某些操作(例如循环处理一大组数据)要花费很长时间来执行,因此它们会妨碍主应用程序线程足够快地更新屏幕。这可能会导致屏幕延迟或冻结。
使用 worker 可允许您在后台执行长时间运行的或慢速的操作。每个 worker 都在独立于其他 worker 的一个单独的执行线程中运行自己的代码。一个 worker 中的长时间运行代码不会阻止另一个 worker 中的代码执行。相反,两组代码可以并行运行。因此,可以使用一个 worker 在后台执行代码,同时主应用程序线程仍然能够自由地继续更新屏幕。
同时执行多组代码指令的这一功能称为并发。
注意:在桌面平台上,Flash Player 和 AIR 均支持使用 worker 实现并发。对于移动平台,AIR Android 和 iOS 均支持并发。在尝试使用并发之前,您可以使用 isSupported 静态属性来检查是否支持并发。
不要通过调用 Worker()
构造函数来直接创建 Worker 实例。在支持使用 worker 实现并发的上下文中,在启动时运行时会自动创建与主 SWF 关联的 Worker(称为原始 worker)。
每个额外的 worker 都是基于一个单独的 swf 创建的。要创建 Worker 类的新实例,请将一个 ByteArray(其中包含后台 worker 的 swf 的字节)作为参数传递给 WorkerDomain 类的 createWorker()
方法。针对此目的,有三种常用方式可用来访问 swf 的字节:
-
使用 [Embed] 元标记将 .swf 文件作为 ByteArray 嵌入在应用程序中:
// Embed the SWF file [Embed(source="../swfs/BgWorker.swf", mimeType="application/octet-stream")] private static var BgWorker_ByteClass:Class; private function createWorker():void { // create the background worker var workerBytes:ByteArray = new BgWorker_ByteClass(); var bgWorker:Worker = WorkerDomain.current.createWorker(workerBytes); // listen for worker state changes to know when the worker is running bgWorker.addEventListener(Event.WORKER_STATE, workerStateHandler); // set up communication between workers using // setSharedProperty(), createMessageChannel(), etc. // ... (not shown) bgWorker.start(); }
-
使用 URLLoader 加载外部 SWF 文件:
// load the SWF file var workerLoader:URLLoader = new URLLoader(); workerLoader.dataFormat = URLLoaderDataFormat.BINARY; workerLoader.addEventListener(Event.COMPLETE, loadComplete); workerLoader.load(new URLRequest("BgWorker.swf")); private function loadComplete(event:Event):void { // create the background worker var workerBytes:ByteArray = event.target.data as ByteArray; var bgWorker:Worker = WorkerDomain.current.createWorker(workerBytes); // listen for worker state changes to know when the worker is running bgWorker.addEventListener(Event.WORKER_STATE, workerStateHandler); // set up communication between workers using // setSharedProperty(), createMessageChannel(), etc. // ... (not shown) bgWorker.start(); }
-
将单个 swf 同时用作原始 worker 和后台 worker:
// The primordial worker's main class constructor public function PrimordialWorkerClass() { init(); } private function init():void { var swfBytes:ByteArray = this.loaderInfo.bytes; // Check to see if this is the primordial worker if (Worker.current.isPrimordial) { // create a background worker var bgWorker:Worker = WorkerDomain.current.createWorker(swfBytes); // listen for worker state changes to know when the worker is running bgWorker.addEventListener(Event.WORKER_STATE, workerStateHandler); // set up communication between workers using // setSharedProperty(), createMessageChannel(), etc. // ... (not shown) bgWorker.start(); } else // entry point for the background worker { // set up communication between workers using getSharedProperty() // ... (not shown) // start the background work } }
Worker 彼此独立地执行并且不访问相同的内存、变量和代码。不过,有三种机制可用来在 Worker 实例之间传递消息和数据:
- 共享属性:每个 worker 都有可以从该 worker 自身及其他 worker 设置和读取的一组内部命名值。您可以使用
setSharedProperty()
方法来设置值并使用getSharedProperty()
方法来读取值。 - MessageChannel:MessageChannel 对象允许您将单向消息和数据从一个 worker 发送到另一个 worker。接收 worker 中的代码可以侦听当有消息到达时要通知的事件。要创建 MessageChannel 对象,请使用
createMessageChannel()
方法。 - 可共享 ByteArray:如果 ByteArray 对象的
shareable
属性为true
,则所有 worker 中该 ByteArray 的实例都使用相同的底层内存。由于多个 worker 中的代码可以同时访问共享内存,因此您的代码应使用ByteArray.shareable
属性说明中描述的机制,以避免发生数据意外更改问题。
在后台 worker 中运行的代码中,有多个运行时 API 不可用。这主要包括与用户输入和输出机制相关的 API,或者与操作系统元素(例如窗口和拖拽)相关的 API。作为一个规则,对于不是在所有上下文中都受支持的任何 API,在尝试使用该 API 之前,请使用 isSupported
、available
和类似属性来检查该 API 在后台 worker 上下文中是否可用。
注意:本机扩展不支持背景和辅助 worker。
Worker 非常有用,因为它们可以减少由于主渲染线程受其他代码阻止而使帧速率下降的可能。但是,worker 需要使用额外系统内存和 CPU,这可能使整体应用程序性能代价昂贵。由于每个 worker 均使用其自身的运行时虚拟机实例,因此即使不重要的 worker 开销也可能很大。当使用 worker 时,请在所有目标平台测试代码,以确保对系统的需求不是太大。Adobe 建议在典型情境下请勿使用超过一个或两个后台 worker。
了解详细信息
AS3 Worker 介绍:Shawn Blais 开发的图像处理功能
多线程物理:将 AS3 Worker 用于 Shawn Blaiss 开发的物理引擎
相关 API 元素
属性 | 由以下参数定义 | ||
---|---|---|---|
constructor : Object
对类对象或给定对象实例的构造函数的引用。 | Object | ||
current : Worker [静态] [只读]
提供对包含当前代码的 worker 的访问
| Worker | ||
isPrimordial : Boolean [只读]
指示此 worker 是否为原始 worker。 | Worker | ||
isSupported : Boolean [静态] [只读]
指示当前运行时上下文是否支持将 Worker 对象用于并行代码执行。 | Worker | ||
state : String [只读]
worker 在其生命周期中的当前状态。 | Worker |
方法 | 由以下参数定义 | ||
---|---|---|---|
addEventListener(type:String, listener:Function, useCapture:Boolean = false, priority:int = 0, useWeakReference:Boolean = false):void [覆盖]
使用 EventDispatcher 对象注册事件侦听器对象,以使侦听器能够接收事件通知。 | Worker | ||
创建一个新的 MessageChannel 实例来将消息从调用此方法的 worker 发送到另一个接收方 worker。 | Worker | ||
将事件调度到事件流中。 | EventDispatcher | ||
通过指定的键检索存储在此 worker 中的值。 | Worker | ||
检查 EventDispatcher 对象是否为特定事件类型注册了任何侦听器。 | EventDispatcher | ||
表示对象是否已经定义了指定的属性。 | Object | ||
表示 Object 类的实例是否在指定为参数的对象的原型链中。 | Object | ||
表示指定的属性是否存在、是否可枚举。 | Object | ||
[覆盖]
从 EventDispatcher 对象中删除侦听器。 | Worker | ||
设置循环操作动态属性的可用性。 | Object | ||
提供可供在 worker 的 swf 中运行的代码使用的具名值。 | Worker | ||
启动 worker 的执行。 | Worker | ||
停止 worker 的代码执行。 | Worker | ||
返回此对象的字符串表示形式,其格式设置遵守区域设置特定的约定。 | Object | ||
返回指定对象的字符串表示形式。 | Object | ||
返回指定对象的原始值。 | Object | ||
检查是否用此 EventDispatcher 对象或其任何祖代为指定事件类型注册了事件侦听器。 | EventDispatcher |
事件 | 摘要 | 由以下参数定义 | ||
---|---|---|---|---|
[广播事件] Flash Player 或 AIR 应用程序获得操作系统焦点并变为活动状态时将调度此事件。 | EventDispatcher | |||
[广播事件] Flash Player 或 AIR 应用程序失去操作系统焦点并变为非活动状态时将调度此事件。 | EventDispatcher | |||
当 worker 的 state 属性改变时将调度此事件。 | Worker |
current | 属性 |
isPrimordial | 属性 |
isPrimordial:Boolean
[只读] 语言版本: | ActionScript 3.0 |
运行时版本: | Flash Player 11.4, AIR 3.4 |
指示此 worker 是否为原始 worker。
原始 worker 是运行初始 swf 的 worker。此 worker 控制对屏幕的渲染。
可以使用此属性构建一个应用程序,使其中的原始 worker 和后台 worker 是同一 swf 文件的两个实例。替代方法是相应地构造您的代码,让后台 worker 使用编译为与原始 worker 不同的 swf 的代码。
实现
public function get isPrimordial():Boolean
isSupported | 属性 |
state | 属性 |
addEventListener | () | 方法 |
override public function addEventListener(type:String, listener:Function, useCapture:Boolean = false, priority:int = 0, useWeakReference:Boolean = false):void
语言版本: | ActionScript 3.0 |
运行时版本: | Flash Player 11.4, AIR 3.4 |
使用 EventDispatcher 对象注册事件侦听器对象,以使侦听器能够接收事件通知。可以为特定类型的事件、阶段和优先级在显示列表中的所有节点上注册事件侦听器。
成功注册一个事件侦听器后,无法通过额外调用 addEventListener()
来更改其优先级。要更改侦听器的优先级,必须首先调用 removeListener()
。然后,可以使用新的优先级再次注册该侦听器。
请记住,注册该侦听器后,如果继续调用具有不同 type
或 useCapture
值的 addEventListener()
,则会创建单独的侦听器注册。例如,如果首先注册 useCapture
设置为 true
的侦听器,则该侦听器只在捕获阶段进行侦听。如果使用同一个侦听器对象再次调用 addEventListener()
,并将 useCapture
设置为 false
,那么便会拥有两个单独的侦听器:一个在捕获阶段进行侦听,另一个在目标和冒泡阶段进行侦听。
不能只为目标阶段或冒泡阶段注册事件侦听器。这些阶段在注册期间是成对出现的,因为冒泡阶段只适用于目标节点的祖代。
如果不再需要某个事件侦听器,可调用 removeEventListener()
删除它,否则会产生内存问题。事件侦听器不会自动从内存中删除,因为只要调度对象存在,垃圾回收器就不会删除侦听器(除非 useWeakReference
参数设置为 true
)。
复制 EventDispatcher 实例时并不复制其中附加的事件侦听器。(如果新近创建的节点需要一个事件侦听器,必须在创建该节点后附加该侦听器。)但是,如果移动 EventDispatcher 实例,则其中附加的事件侦听器也会随之移动。
如果在正在处理事件的节点上注册事件侦听器,则不会在当前阶段触发事件侦听器,但会在事件流的稍后阶段触发,如冒泡阶段。
如果从正在处理事件的节点中删除事件侦听器,则该事件侦听器仍由当前操作触发。删除事件侦听器后,决不会再次调用该事件侦听器(除非再次注册以备将来处理)。
参数
type:String — 事件的类型。
| |
listener:Function — 处理事件的侦听器函数。此函数必须接受 Event 对象作为其唯一的参数,并且不能返回任何结果,如下面的示例所示:
function(evt:Event):void 函数可以有任何名称。 | |
useCapture:Boolean (default = false ) —
确定侦听器是运行于捕获阶段还是运行于目标和冒泡阶段。如果将 useCapture 设置为 true ,则侦听器只在捕获阶段处理事件,而不在目标或冒泡阶段处理事件。如果 useCapture 为 false ,则侦听器只在目标或冒泡阶段处理事件。要在所有三个阶段都侦听事件,请调用 addEventListener 两次:一次将 useCapture 设置为 true ,一次将 useCapture 设置为 false 。
| |
priority:int (default = 0 ) — 事件侦听器的优先级。优先级由一个带符号的 32 位整数指定。数字越大,优先级越高。优先级为 n 的所有侦听器会在优先级为 n -1 的侦听器之前得到处理。如果两个或更多个侦听器共享相同的优先级,则按照它们的添加顺序进行处理。默认优先级为 0。
| |
useWeakReference:Boolean (default = false ) — 确定对侦听器的引用是强引用,还是弱引用。强引用(默认值)可防止您的侦听器被当作垃圾回收。弱引用则没有此作用。 类级别成员函数不属于垃圾回收的对象,因此可以对类级别成员函数将 |
createMessageChannel | () | 方法 |
public function createMessageChannel(receiver:Worker):MessageChannel
语言版本: | ActionScript 3.0 |
运行时版本: | Flash Player 11.4, AIR 3.4 |
创建一个新的 MessageChannel 实例来将消息从调用此方法的 worker 发送到另一个接收方 worker。创建 MessageChannel 对象的 worker 中的代码可以使用它将单向消息发送到作为 receiver
参数指定的 Worker 对象。
虽然可以使用 MessageChannel 实例来将消息和数据从一个 Worker 实例发送到另一个,但是至少需要通过调用 Worker 对象的 setSharedProperty()
方法将一个 MessageChannel 实例作为共享属性传递给一个子 Worker。
outgoingChannel = Worker.current.createMessageChannel(bgWorker); incomingChannel = bgWorker.createMessageChannel(Worker.current); bgWorker.setSharedProperty("incoming", outgoingChannel); bgWorker.setSharedProperty("outgoing", incomingChannel); // listen for messages from the receiving MessageChannel // This event is triggered when the background sends a message to this worker incomingChannel.addEventListener(Event.CHANNEL_MESSAGE, incomingMessageHandler);
参数
receiver:Worker — 将接收通过所创建的消息通道传送的消息的 worker
|
MessageChannel — 操作所创建的 MessageChannel 对象
|
getSharedProperty | () | 方法 |
removeEventListener | () | 方法 |
override public function removeEventListener(type:String, listener:Function, useCapture:Boolean = false):void
语言版本: | ActionScript 3.0 |
运行时版本: | Flash Player 11.4, AIR 3.4 |
从 EventDispatcher 对象中删除侦听器。如果没有向 EventDispatcher 对象注册任何匹配的侦听器,则对此方法的调用没有任何效果。
参数
type:String — 事件的类型。
| |
listener:Function — 要删除的侦听器对象。
| |
useCapture:Boolean (default = false ) —
指出是为捕获阶段还是为目标和冒泡阶段注册了侦听器。如果为捕获阶段以及目标和冒泡阶段注册了侦听器,则需要对 removeEventListener() 进行两次调用才能将这两个侦听器删除,一次调用将 useCapture() 设置为 true ,另一次调用将 useCapture() 设置为 false 。
|
setSharedProperty | () | 方法 |
public function setSharedProperty(key:String, value:*):void
语言版本: | ActionScript 3.0 |
运行时版本: | Flash Player 11.4, AIR 3.4 |
提供可供在 worker 的 swf 中运行的代码使用的具名值。
您可以在调用 worker 的 start()
方法之前调用此方法。在这种情况下,在构造时共享属性可供 worker 的 swf 中的代码使用。
传递到 value
参数的值几乎可以是任何对象。除了下面指出的例外,传递到 value
参数的任何对象都不是按引用传递的。在调用 setSharedProperty()
后对一个 worker 中的对象所做的更改不会保留到另一个 worker。对象是通过序列化为 AMF3 格式以及反序列化为接收 worker 中的一个新对象进行复制的。因此,无法以 AMF3 格式进行序列化的任何对象(包括显示对象)都不能传递给 value
参数。为了使自定义类能够被正确传递,必须使用 flash.net.registerClassAlias()
函数或 [RemoteClass]
元数据来注册类定义。无论使用哪种方法,都必须为类的两个 worker 版本使用相同的别名。
有五种对象例外,对它们不适用对象不在 worker 之间共享的规则:
- Worker
- MessageChannel
- 可共享 ByteArray(其
shareable
属性设为true
的 ByteArray 对象) - Mutex
- Condition
如果您将这些对象的一个实例传递给 value
参数,则每个 worker 都将引用同一个底层对象。在一个 worker 中对实例所做的更改可立即用于另一 worker 中。此外,如果您多次使用 setSharedProperty()
传递了这些对象的同一实例,则运行时不会在接收 worker 中创建对象的新副本。相反,它将重用同一引用,这降低了对系统内存的使用。
以 null
或 undefined
作为 value
参数调用此方法将清除指定 key
参数的任何以前任何值。以这种方式清除某个值将删除对该值的引用,从而允许对该值进行垃圾回收。
您可以在 key 参数中使用任何 String 值。这些共享属性可供对 worker 具有访问权限的任何代码使用。为避免意外覆盖某个值,请考虑使用前缀、后缀或类似机制来尝试使您的键名称成为唯一的。
参数
key:String — 存储共享属性时使用的名称。
| |
value:* — 共享属性的值。
|
相关 API 元素
start | () | 方法 |
public function start():void
语言版本: | ActionScript 3.0 |
运行时版本: | Flash Player 11.4, AIR 3.4 |
启动 worker 的执行。运行时创建 worker 线程并调用 worker swf 的主类的构造函数。
此操作是异步的。一旦 worker 启动完成,它会将其 state
属性更改为 WorkerState.RUNNING
并调度一个 workerState
事件。
terminate | () | 方法 |
workerState | 事件 |
flash.events.Event
属性 Event.type =
flash.events.Event.WORKER_STATE
语言版本: | ActionScript 3.0 |
运行时版本: | Flash Player 11.4, AIR 3.4 |
当 worker 的 state
属性改变时将调度此事件。
Event.WORKER_STATE
常量定义 workerState
事件对象的 type
属性的值。
此事件具有以下属性:
属性 | 值 |
---|---|
bubbles | false |
cancelable | false ;没有要取消的默认行为。 |
currentTarget | 当前正在使用某个事件侦听器处理 Event 对象的对象。 |
target | 调度此事件的对象。 |
此示例包括三个 ActionScript 类:WorkerExample 是主类和父 worker。BackgroundWorker 是执行后台工作的类。它被编译为后台 worker swf 的主类。CountResult 是一个自定义类,用来将数据作为单个对象而不是作为多个值在两个 worker 之间传递。
在此示例中,后台 worker 在一个循环中进行计数,直至达到父 worker 指定的数目。随着其工作的进展,它会向父 worker 发送进度消息。最后,当计数完成时,后台 worker 会向父 worker 发送一条消息来通知它已完成以及它花费了多长时间来计数。
WorkerExample 类是 swf 的主类,因此它是原始 worker 的主类。在 initialize()
方法中,代码使用 BackgroundWorker 类的字节(它们是使用 [Embed]
标记嵌入的)创建后台 worker 对象。
在通过调用 WorkerDomain.createWorker()
创建后台 worker 后,代码将设置 worker 之间的通信。首先,代码创建一组 MessageChannel 对象。它通过调用后台 worker 的 setSharedProperty()
方法将这些对象传递给后台 worker。最后,它注册后台 Worker 对象的 workerState
事件并通过调用其 start()
方法启动该 worker。
随着后台 worker 执行其工作,它会将进度(以及最终结果)消息发送到父 worker。父 worker 使用该信息来更新进度栏和文本指示器。
package { import com.adobe.example.vo.CountResult; import flash.display.Shape; import flash.display.Sprite; import flash.display.StageAlign; import flash.display.StageScaleMode; import flash.events.Event; import flash.net.registerClassAlias; import flash.system.MessageChannel; import flash.system.Worker; import flash.system.WorkerDomain; import flash.system.WorkerState; import flash.text.TextField; import flash.text.TextFormat; import flash.text.TextFormatAlign; import flash.utils.ByteArray; public class WorkerExample extends Sprite { // ------- Embed the background worker swf as a ByteArray ------- [Embed(source="../workerswfs/BackgroundWorker.swf", mimeType="application/octet-stream")] private static var BackgroundWorker_ByteClass:Class; public static function get BackgroundWorker():ByteArray { return new BackgroundWorker_ByteClass(); } private var bgWorker:Worker; private var bgWorkerCommandChannel:MessageChannel; private var progressChannel:MessageChannel; private var resultChannel:MessageChannel; public function WorkerExample() { initialize(); } private function initialize():void { // create the user interface setupStage(); createStatusText(); createProgressBar(); // Register the alias so we can pass CountResult objects between workers registerClassAlias("com.adobe.test.vo.CountResult", CountResult); // Create the background worker bgWorker = WorkerDomain.current.createWorker(BackgroundWorker); // Set up the MessageChannels for communication between workers bgWorkerCommandChannel = Worker.current.createMessageChannel(bgWorker); bgWorker.setSharedProperty("incomingCommandChannel", bgWorkerCommandChannel); progressChannel = bgWorker.createMessageChannel(Worker.current); progressChannel.addEventListener(Event.CHANNEL_MESSAGE, handleProgressMessage) bgWorker.setSharedProperty("progressChannel", progressChannel); resultChannel = bgWorker.createMessageChannel(Worker.current); resultChannel.addEventListener(Event.CHANNEL_MESSAGE, handleResultMessage); bgWorker.setSharedProperty("resultChannel", resultChannel); // Start the worker bgWorker.addEventListener(Event.WORKER_STATE, handleBGWorkerStateChange); bgWorker.start(); } private function handleBGWorkerStateChange(event:Event):void { if (bgWorker.state == WorkerState.RUNNING) { _statusText.text = "Background worker started"; bgWorkerCommandChannel.send(["startCount", 100000000]); } } private function handleProgressMessage(event:Event):void { var percentComplete:Number = progressChannel.receive(); setPercentComplete(percentComplete); _statusText.text = Math.round(percentComplete).toString() + "% complete"; } private function handleResultMessage(event:Event):void { var result:CountResult = resultChannel.receive() as CountResult; setPercentComplete(100); _statusText.text = "Counted to " + result.countTarget + " in " + (Math.round(result.countDurationSeconds * 10) / 10) + " seconds"; } // ------- Create UI ------- private var _currentPercentComplete:int = 0; private var _needsValidation:Boolean = false; private var _statusText:TextField; private var _progressBarRect:Shape; private var _progressBar:Shape; private function setupStage():void { stage.align = StageAlign.TOP_LEFT; stage.scaleMode = StageScaleMode.NO_SCALE; stage.stageWidth = 800; stage.stageHeight = 600; stage.color = 0xffffff; } private function createStatusText():void { _statusText = new TextField(); _statusText.width = 400; _statusText.height = 25; _statusText.x = (stage.stageWidth - _statusText.width) / 2; _statusText.y = 150; var statusTextFormat:TextFormat = new TextFormat(); statusTextFormat.color = 0xeeeeee; statusTextFormat.font = "Verdana"; statusTextFormat.align = TextFormatAlign.CENTER; statusTextFormat.size = 16; _statusText.defaultTextFormat = statusTextFormat; _statusText.wordWrap = false; _statusText.opaqueBackground = 0x999999; _statusText.selectable = false; _statusText.text = "Initializing..."; addChild(_statusText); } private function createProgressBar():void { _progressBarRect = new Shape(); _progressBarRect.graphics.beginFill(0x000000, 0); _progressBarRect.graphics.lineStyle(2, 0x000000); _progressBarRect.graphics.drawRect(0, 0, 400, 30); _progressBarRect.graphics.endFill(); _progressBarRect.x = (stage.stageWidth - _progressBarRect.width) / 2; _progressBarRect.y = 100; addChild(_progressBarRect); _progressBar = new Shape(); _progressBar.graphics.beginFill(0x0000ee); _progressBar.graphics.drawRect(0, 0, 391, 21); _progressBar.x = _progressBarRect.x + 4; _progressBar.y = _progressBarRect.y + 4; addChild(_progressBar); _progressBar.scaleX = 0; } private function setPercentComplete(percentComplete:int):void { if (_currentPercentComplete == percentComplete) return; _currentPercentComplete = percentComplete; invalidateValue(); } private function invalidateValue():void { if (_needsValidation) return; _needsValidation = true; addEventListener(Event.EXIT_FRAME, validate); } private function validate(event:Event):void { removeEventListener(Event.EXIT_FRAME, validate); _needsValidation = false; _redrawProgressBar(); } private function _redrawProgressBar():void { _progressBar.scaleX = _currentPercentComplete / 100; } } }
在 initialize()
方法中,它接收父 worker 传递的 MessageChannel 对象。它们用于两个 worker 之间的通信。
父 worker 在 commandChannel
消息通道上调用 send()
方法来发送消息。在后台 worker 内,运行时然后通过调用 handleCommandMessage()
方法来调度 channelMessage
事件。
后台 worker 的实际工作发生在 count()
方法中。随着后台 worker 执行其计数,它会通过在 progressChannel
MessageChannel 对象上调用 send()
方法将进度消息发送到父 worker。当它完成计数时,它将在 resultChannel
MessageChannel 对象上调用 send()
方法。
package com.adobe.example.workers { import com.adobe.example.vo.CountResult; import flash.display.Sprite; import flash.events.Event; import flash.net.registerClassAlias; import flash.system.MessageChannel; import flash.system.Worker; import flash.utils.getTimer; public class BackgroundWorker extends Sprite { private var commandChannel:MessageChannel; private var progressChannel:MessageChannel; private var resultChannel:MessageChannel; public function BackgroundWorker() { initialize(); } private function initialize():void { registerClassAlias("com.adobe.test.vo.CountResult", CountResult); // Get the MessageChannel objects to use for communicating between workers // This one is for receiving messages from the parent worker commandChannel = Worker.current.getSharedProperty("incomingCommandChannel") as MessageChannel; commandChannel.addEventListener(Event.CHANNEL_MESSAGE, handleCommandMessage); // These are for sending messages to the parent worker progressChannel = Worker.current.getSharedProperty("progressChannel") as MessageChannel; resultChannel = Worker.current.getSharedProperty("resultChannel") as MessageChannel; } private function handleCommandMessage(event:Event):void { if (!commandChannel.messageAvailable) return; var message:Array = commandChannel.receive() as Array; if (message != null && message[0] == "startCount") { count(uint(message[1])); } } private function count(targetValue:uint):void { var startTime:int = getTimer(); var onePercent:uint = uint(Math.ceil(targetValue / 100)); var oneHalfPercent:Number = onePercent / 2; var i:uint = 0; while (i < targetValue) { i++; // only send progress messages every one-half-percent milestone // to avoid flooding the message channel if (i % oneHalfPercent == 0) { progressChannel.send(i / onePercent); } } var elapsedTime:int = getTimer() - startTime; var result:CountResult = new CountResult(targetValue, elapsedTime / 1000); resultChannel.send(result); trace("counted to", targetValue.toString(), "in", elapsedTime, "milliseconds"); } } }
registerClassAlias()
方法。
package com.adobe.example.vo { public class CountResult { public function CountResult(countTarget:uint=0, countTime:Number=0) { this.countTarget = countTarget; this.countDurationSeconds = countTime; } public var countTarget:uint; public var countDurationSeconds:Number; } }
1. 由于动态加载包含 ActionScript 代码的远程 SWF 不起作用,因此必须将远程 SWF 作为去除内容的 SWF 传递给 worker。2. 使用 [Embed] 标记嵌入 SWF(具有 ABC 代码)在 iOS 中无效。每个额外的 worker 都是基于一个单独的 swf 创建的。要创建 Worker 类的新实例,请将一个 ByteArray(其中包含后台 worker 的 SWF 的字节)作为参数传递给 WorkerDomain 类的 createWorker()
方法。
在 iOS 上实现此目的时,有两种常用方式可用来访问 SWF 的字节:第一种方法是使用 Loader
加载一个外部 SWF 文件,第二种方法是使用 URLLoader
加载 SWF 文件。
下例使用 Loader
API 加载 SWF 文件。
package { import flash.display.Loader; import flash.display.Sprite; import flash.display.StageAlign; import flash.display.StageScaleMode; import flash.events.Event; import flash.events.IOErrorEvent; import flash.net.URLRequest; import flash.system.ApplicationDomain; import flash.system.LoaderContext; import flash.system.MessageChannel; import flash.system.Worker; import flash.system.WorkerDomain; import flash.text.TextField; import flash.text.TextFormat; public class IOSWorkerExample extends Sprite { public var worker:Worker; public var bm:MessageChannel; public var mb:MessageChannel; public var tf:TextField; public var tfrmt:TextFormat; public function IOSWorkerExample() { super(); stage.align = StageAlign.TOP_LEFT; stage.scaleMode = StageScaleMode.NO_SCALE; tf=new TextField(); tfrmt= new TextFormat() tfrmt.size=80; tf.textColor = 0xFFFFF; tf.defaultTextFormat=tfrmt; addChild(tf); //creating the urlRequest object that references the background worker. var _urlRequest:URLRequest = new URLRequest("IOSBackWorker.swf"); var _loader:Loader = new Loader(); var _lc:LoaderContext = new LoaderContext(false, ApplicationDomain.currentDomain, null); _loader.contentLoaderInfo.addEventListener(Event.COMPLETE,completeHandler); _loader.contentLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR,errorHandler); _loader.load(_urlRequest, _lc); } // This function is called once the swf loading is completed public function completeHandler(e:Event):void { worker = WorkerDomain.current.createWorker(e.target.bytes); bm = worker.createMessageChannel(Worker.current); mb = Worker.current.createMessageChannel(worker); worker.setSharedProperty("btm", bm); worker.setSharedProperty("mtb", mb); //adding event handler on message receive from background bm.addEventListener(Event.CHANNEL_MESSAGE, onBackToMain); worker.start(); bm.receive(true); } public function errorHandler(e:IOErrorEvent):void { trace("In IO ErrorEvent Handler "+e.text); } //This function is called when the main thread receives the message from the background worker. public function onBackToMain(event:Event):void { if(bm.messageAvailable) { // displaying the percentages based on the message received from the background. var progress:Number = bm.receive(); trace("progress "+progress); tf.text= progress.toString(); } } } }
Loader
的加载功能时,如果正在执行此代码,我们需要在后台 worker 中放置一个 isPrimordial
属性检查语句。
package { import flash.display.Sprite; import flash.system.MessageChannel; import flash.system.Worker; import flash.utils.ByteArray; import flash.utils.getTimer; public class IOSBackWorker extends Sprite { private var memory:ByteArray = new ByteArray(); private var bm:MessageChannel; private var mb:MessageChannel; public function IOSBackWorker() { if(!Worker.current.isPrimordial) { memory.shareable = true; // creating objects of message channels bm = Worker.current.getSharedProperty("btm"); mb = Worker.current.getSharedProperty("mtb"); // calculating the percentage trace("message came"); var j:Number =1; while (j<1000) { for(var i=0;i<100;i++){} var startTime=getTimer(); // adding delay while (getTimer()-startTime <100); trace(j, (100*j)/1000); var progress:Number=(100*j)/1000; // sending the percentage to the main thread bm.send(progress); j++; } } } } }
Tue Jun 12 2018, 11:04 AM Z