Package | flash.system |
Class | public final class Worker |
Inheritance | Worker EventDispatcher Object |
Language Version: | ActionScript 3.0 |
Runtime Versions: | Flash Player 11.4, AIR 3.4 |
A worker allows you to execute code "in the background" at the same time that other operations are running in another worker (including the main swf's worker). In a non-worker context some operations, for example processing a large set of data in a loop, take so long to execute that they prevent the main application thread from updating the screen quickly enough. This can cause stuttering or freezing the screen.
Using a worker allows you to perform a long-running or slow operation in the background. Each worker runs its code in a separate thread of execution from other workers. Long-running code in one worker does not block code in another worker from executing. Instead, the two sets of code run in parallel. Consequently, a worker can be used to execute code in the background while the main application thread stays free to continue updating the screen.
This capability of simultaneously executing multiple sets of code instructions is known as concurrency.
Note: The use of workers for concurrency is supported in both Flash Player and AIR on desktop platforms. For mobile platforms, concurrency is supported in AIR on both Android and iOS. You can use the static isSupported property to check whether concurrency is supported before attempting to use it.
You do not create Worker instances directly by calling the
Worker()
constructor. In contexts where the use of workers for
concurrency is supported, at startup the runtime automatically creates the
Worker associated with the main SWF, known as the primordial worker.
Each additional worker is created from a separate swf. To create a new
instance of the Worker class, pass a ByteArray with the bytes of the
background worker's swf as an argument to the WorkerDomain class's
createWorker()
method. There are three common ways to access the
bytes of a swf for this purpose:
-
Use the [Embed] metatag to embed the .swf file in the application as a 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(); }
-
Load an external SWF file using a URLLoader:
// 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(); }
-
Use a single swf as both the primordial worker and the background 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 } }
Workers execute in isolation from each other and do not have access to the same memory, variables, and code. However, there are three mechanisms available for passing messages and data between Worker instances:
- Shared properties: Each worker has an internal set of named values
that can be set and read both from within the worker itself as well as from
other workers. You can set a value using the
setSharedProperty()
method and read a value using thegetSharedProperty()
method. - MessageChannel: A MessageChannel object allows you to send one-way
messages and data from one worker to another. Code in the receiving
worker can listen for an event to be notified when a message arrives.
To create a MessageChannel object, use the
createMessageChannel()
method. - Shareable ByteArray: If a ByteArray object's
shareable
property istrue
, the same underlying memory is used for instances of that ByteArray in all workers. Because code in multiple workers can access the shared memory at the same time, your code should use the mechanisms described in theByteArray.shareable
property description to avoid problems from unexpected data changes.
Several runtime APIs are not available in code running in a background
worker. These primarily consist of APIs related to user input and output
mechanisms, or operating system elements like windows and dragging. As a
rule, for any API that isn't supported in all contexts, use the
isSupported
, available
, and similar properties to
check whether the API is available in the background worker context before
attempting to use the API.
Note: Native Extensions are not supported for background and secondary workers.
Workers are useful because they decrease the chances of the frame rate dropping due to the main rendering thread being blocked by other code. However, workers require additional system memory and CPU use, which can be costly to overall application performance. Because each worker uses its own instance of the runtime virtual machine, even the overhead of a trivial worker can be large. When using workers, test your code across all your target platforms to ensure that the demands on the system are not too large. Adobe recommends that you do not use more than one or two background workers in a typical scenario.
More examples
Learn more
Intro to AS3 Workers: Image Processing by Shawn Blais
Multithreaded Physics: Using AS3 Workers for a physics engine by Shawn Blais
Related API Elements
Property | Defined By | ||
---|---|---|---|
constructor : Object
A reference to the class object or constructor function for a given object instance. | Object | ||
current : Worker [static] [read-only]
Provides access to the worker that contains the current code
| Worker | ||
isPrimordial : Boolean [read-only]
Indicates whether this worker is the primordial worker. | Worker | ||
isSupported : Boolean [static] [read-only]
Indicates whether the current runtime context supports the use of Worker
objects for concurrent code execution. | Worker | ||
state : String [read-only]
The current state of the worker in its lifecycle. | Worker |
Method | Defined By | ||
---|---|---|---|
addEventListener(type:String, listener:Function, useCapture:Boolean = false, priority:int = 0, useWeakReference:Boolean = false):void [override]
Registers an event listener object with an EventDispatcher object so that the listener
receives notification of an event. | Worker | ||
Creates a new MessageChannel instance to send messages from the worker on
which the method is called to another receiver worker. | Worker | ||
Dispatches an event into the event flow. | EventDispatcher | ||
Retrieves a value stored in this worker with a named key. | Worker | ||
Checks whether the EventDispatcher object has any listeners registered for a specific type
of event. | EventDispatcher | ||
Indicates whether an object has a specified property defined. | Object | ||
Indicates whether an instance of the Object class is in the prototype chain of the object specified
as the parameter. | Object | ||
Indicates whether the specified property exists and is enumerable. | Object | ||
[override]
Removes a listener from the EventDispatcher object. | Worker | ||
Sets the availability of a dynamic property for loop operations. | Object | ||
Provides a named value that is available to code running in the worker's swf. | Worker | ||
Starts the execution of the worker. | Worker | ||
Stops this worker's code execution. | Worker | ||
Returns the string representation of this object, formatted according to locale-specific conventions. | Object | ||
Returns the string representation of the specified object. | Object | ||
Returns the primitive value of the specified object. | Object | ||
Checks whether an event listener is registered with this EventDispatcher object or any of
its ancestors for the specified event type. | EventDispatcher |
Event | Summary | Defined By | ||
---|---|---|---|---|
[broadcast event] Dispatched when the Flash Player or AIR application gains operating system focus and becomes active. | EventDispatcher | |||
[broadcast event] Dispatched when the Flash Player or AIR application operating loses system focus and is becoming inactive. | EventDispatcher | |||
Dispatched when the value of the worker's state property changes. | Worker |
current | property |
isPrimordial | property |
isPrimordial:Boolean
[read-only] Language Version: | ActionScript 3.0 |
Runtime Versions: | Flash Player 11.4, AIR 3.4 |
Indicates whether this worker is the primordial worker.
The primordial worker is the worker in which the initial swf is running. This worker controls the rendering to the screen.
This property can be used to architect an application where the primordial worker and the background worker are two instances of the same swf file. The alternative is to structure your code so that the background worker uses different code compiled to a different swf from the primorial worker.
Implementation
public function get isPrimordial():Boolean
isSupported | property |
isSupported:Boolean
[read-only] Language Version: | ActionScript 3.0 |
Runtime Versions: | Flash Player 11.4, AIR 3.4 |
Indicates whether the current runtime context supports the use of Worker objects for concurrent code execution.
If concurrency is available, this property's value is true
.
Implementation
public static function get isSupported():Boolean
state | property |
addEventListener | () | method |
override public function addEventListener(type:String, listener:Function, useCapture:Boolean = false, priority:int = 0, useWeakReference:Boolean = false):void
Language Version: | ActionScript 3.0 |
Runtime Versions: | Flash Player 11.4, AIR 3.4 |
Registers an event listener object with an EventDispatcher object so that the listener receives notification of an event. You can register event listeners on all nodes in the display list for a specific type of event, phase, and priority.
After you successfully register an event listener, you cannot change its priority
through additional calls to addEventListener()
. To change a listener's
priority, you must first call removeListener()
. Then you can register the
listener again with the new priority level.
Keep in mind that after the listener is registered, subsequent calls to
addEventListener()
with a different type
or
useCapture
value result in the creation of a separate listener registration.
For example, if you first register a listener with useCapture
set to
true
, it listens only during the capture phase. If you call
addEventListener()
again using the same listener object, but with
useCapture
set to false
, you have two separate listeners: one
that listens during the capture phase and another that listens during the target and
bubbling phases.
You cannot register an event listener for only the target phase or the bubbling phase. Those phases are coupled during registration because bubbling applies only to the ancestors of the target node.
If you no longer need an event listener, remove it by calling
removeEventListener()
, or memory problems could result. Event listeners are not automatically
removed from memory because the garbage
collector does not remove the listener as long as the dispatching object exists (unless the useWeakReference
parameter is set to true
).
Copying an EventDispatcher instance does not copy the event listeners attached to it. (If your newly created node needs an event listener, you must attach the listener after creating the node.) However, if you move an EventDispatcher instance, the event listeners attached to it move along with it.
If the event listener is being registered on a node while an event is being processed on this node, the event listener is not triggered during the current phase but can be triggered during a later phase in the event flow, such as the bubbling phase.
If an event listener is removed from a node while an event is being processed on the node, it is still triggered by the current actions. After it is removed, the event listener is never invoked again (unless registered again for future processing).
Parameters
type:String — The type of event.
| |
listener:Function — The listener function that processes the event. This function must accept
an Event object as its only parameter and must return nothing, as this example shows:
function(evt:Event):void The function can have any name. | |
useCapture:Boolean (default = false ) —
Determines whether the listener works in the capture phase or the
target and bubbling phases. If useCapture is set to true ,
the listener processes the event only during the capture phase and not in the
target or bubbling phase. If useCapture is false , the
listener processes the event only during the target or bubbling phase. To listen for
the event in all three phases, call addEventListener twice, once with
useCapture set to true , then again with
useCapture set to false .
| |
priority:int (default = 0 ) — The priority level of the event listener. The priority is designated by
a signed 32-bit integer. The higher the number, the higher the priority. All listeners
with priority n are processed before listeners of priority n-1. If two
or more listeners share the same priority, they are processed in the order in which they
were added. The default priority is 0.
| |
useWeakReference:Boolean (default = false ) — Determines whether the reference to the listener is strong or
weak. A strong reference (the default) prevents your listener from being garbage-collected.
A weak reference does not. Class-level member functions are not subject to garbage
collection, so you can set |
createMessageChannel | () | method |
public function createMessageChannel(receiver:Worker):MessageChannel
Language Version: | ActionScript 3.0 |
Runtime Versions: | Flash Player 11.4, AIR 3.4 |
Creates a new MessageChannel instance to send messages from the worker on
which the method is called to another receiver worker. Code in the
worker that creates the MessageChannel object can use it
to send one-way messages to the Worker object specified as
the receiver
argument.
Although a MessageChannel instance can be used to send messages and
data from one Worker instance to another, at least one MessageChannel
instance needs to be passed to a child Worker as a shared property by
calling the Worker object's setSharedProperty()
method.
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);
Parameters
receiver:Worker — The worker that will receive messages transmitted via
the created message channel
|
MessageChannel — The MessageChannel object created by the operation
|
getSharedProperty | () | method |
public function getSharedProperty(key:String):*
Language Version: | ActionScript 3.0 |
Runtime Versions: | Flash Player 11.4, AIR 3.4 |
Retrieves a value stored in this worker with a named key.
Code in a child worker can call this method to retrieve a value as early as in the constructor of the worker swf's main class.
Parameters
key:String — The name of the shared property to retrieve
|
* — The shared property value stored with the specified key, or
null if no value is stored for the specified key
|
removeEventListener | () | method |
override public function removeEventListener(type:String, listener:Function, useCapture:Boolean = false):void
Language Version: | ActionScript 3.0 |
Runtime Versions: | Flash Player 11.4, AIR 3.4 |
Removes a listener from the EventDispatcher object. If there is no matching listener registered with the EventDispatcher object, a call to this method has no effect.
Parameters
type:String — The type of event.
| |
listener:Function — The listener object to remove.
| |
useCapture:Boolean (default = false ) —
Specifies whether the listener was registered for the capture phase or the
target and bubbling phases. If the listener was registered for both the capture phase and the
target and bubbling phases, two calls to removeEventListener() are required
to remove both, one call with useCapture() set to true , and another
call with useCapture() set to false .
|
setSharedProperty | () | method |
public function setSharedProperty(key:String, value:*):void
Language Version: | ActionScript 3.0 |
Runtime Versions: | Flash Player 11.4, AIR 3.4 |
Provides a named value that is available to code running in the worker's swf.
You can call this method before calling the worker's start()
method. In that case the shared property is available to code in the
worker's swf at construction time.
The value passed to the value
parameter can be almost any
object. Other than the exceptions noted below, any object that is passed
to the value
parameter is not passed by reference. Any changes made to the
object in one worker after setSharedProperty()
is called are
not carried over to the other worker. The object is copied by
serializing it to AMF3 format and deserializing it into a new object in the receiving worker.
For this reason, any object that can't be serialized in AMF3 format,
including display objects, can't be passed to the value
parameter.
In order for a custom class to be passed properly, the class definition
must be registered using the flash.net.registerClassAlias()
function or [RemoteClass]
metadata. With either technique
the same alias must be used for both worker's versions of the class.
There are five types of objects that are an exception to the rule that objects aren't shared between workers:
- Worker
- MessageChannel
- shareable ByteArray (a ByteArray object with its
shareable
property set totrue
- Mutex
- Condition
If you pass an instance of these objects to the value
parameter, each worker has a reference to the same underlying object. Changes made to an instance in one worker are immediately available in other workers. In addition, if you pass the same instance of these objects more than once using setSharedProperty()
, the runtime doesn't create a new copy of the object in the receiving worker. Instead, the same reference is re-used, reducing system memory use.
Calling this method with null
or undefined
for the value
argument clears any previously-set value for
the specified key
argument. Cleaning up a value in this way
removes the reference to it, allowing it to be garbage collected.
You can use any String value in the key argument. These shared properties are available to any code that has access to a worker. To avoid unintentionally overwriting a value, consider using a prefix, suffix, or similar mechanism to attempt to make your key names unique.
Parameters
key:String — The name under which the shared property is stored.
| |
value:* — The value of the shared property.
|
Related API Elements
start | () | method |
public function start():void
Language Version: | ActionScript 3.0 |
Runtime Versions: | Flash Player 11.4, AIR 3.4 |
Starts the execution of the worker. The runtime creates the worker thread and calls the constructor of the worker swf's main class.
This operation is asynchronous. Once the worker startup is complete, it
changes its state
property to WorkerState.RUNNING
and dispatches a workerState
event.
terminate | () | method |
public function terminate():Boolean
Language Version: | ActionScript 3.0 |
Runtime Versions: | Flash Player 11.4, AIR 3.4 |
Stops this worker's code execution. Calling this method aborts any current ActionScript in the worker's swf.
ReturnsBoolean — true if code in the worker was running and
interrupted, or false if the worker was never started
|
workerState | Event |
flash.events.Event
property Event.type =
flash.events.Event.WORKER_STATE
Language Version: | ActionScript 3.0 |
Runtime Versions: | Flash Player 11.4, AIR 3.4 |
Dispatched when the value of the worker's state
property changes.
Event.WORKER_STATE
constant defines the value of the type
property of a workerState
event object.
This event has the following properties:
Property | Value |
---|---|
bubbles | false |
cancelable | false ; there is no default behavior to cancel. |
currentTarget | The object that is actively processing the Event object with an event listener. |
target | The object that dispatched this event. |
This example consists of three ActionScript classes: WorkerExample is the main class and the parent worker. BackgroundWorker is the class that does the background work. It's compiled as the main class of the background worker swf. CountResult is a custom class that's used to pass data between the two workers as a single object rather than as multiple values.
In this example, the background worker counts in a loop up to a number specified by the parent worker. As it makes progress in its work it sends progress messages to the parent worker. Finally, when the count is finished the background worker sends a message to the parent worker notifying it that it finished and how long it took to count.
The WorkerExample class is the main class of the swf, so it is the main
class of the primordial worker. In the initialize()
method, the
code creates the background worker object using the bytes of the
BackgroundWorker class, which are embedded using an [Embed]
tag.
After creating the background worker by calling WorkerDomain.createWorker()
,
the code sets up communication between the workers. First the code creates a
set of MessageChannel objects. It passes them to the background worker by
calling its setSharedProperty()
method. Finally it registers for
the background Worker object's workerState
event and starts up
the worker by calling its start()
method.
As the background worker does its work, it sends progress (and eventually result) messages to the parent worker. The parent worker uses this information to update the progress bar and the text indicator.
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; } } }
In the initialize()
method, it receives the MessageChannel
objects that the parent worker passed in. They are used for communication
between the two workers.
The parent worker calls the send()
method on the
commandChannel
message channel to send a message. Inside the
background worker, the runtime then dispatches the channelMessage
event by calling the handleCommandMessage()
method.
The background worker's actual work takes place in the
count()
method. As the background worker proceeds with its count,
it sends progress messages to the parent worker by calling the send()
method on the progressChannel
MessageChannel object. When it
finishes counting, it calls the send()
method on the
resultChannel
MessageChannel object.
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()
method, using the same alias name.
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. As dynamically loading a remote SWF that contains ActionScript code doesn't work,
the remote SWF has to be passed to worker as a stripped SWF.
2. Embedding SWFs(having ABC code) using [Embed] tag will not work on iOS.
Each additional worker is created from a separate SWF. To create a new instance of the Worker class,
pass a ByteArray with the bytes of the background worker's SWF as an argument to the
WorkerDomain class's createWorker()
method.
There are two common ways to access the bytes of a SWF for this purpose on iOS:
The first way is using Loader
to load an external SWF file
and the second is using URLLoader
to load SWF file.
The following example uses Loader
API to load the SWF file.
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
is called, we need to put isPrimordial
property check in background worker as shown in this example.
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++; } } } } }
Thu Dec 6 2018, 01:12 PM -08:00