Pacchetto | flash.system |
Classe | public final class Worker |
Ereditarietà | Worker EventDispatcher Object |
Versione linguaggio: | ActionScript 3.0 |
Versioni runtime: | Flash Player 11.4, AIR 3.4 |
Un worker permette di eseguire il codice "sullo sfondo" (in background), simultaneamente alle altre operazioni in corso di esecuzione in un altro worker (compreso il worker del file SWF principale). In un contesto che non prevede l’uso dei worker, alcune operazioni, ad esempio l’elaborazione di un set di dati di grandi dimensioni in una ripetizione ciclica, possono richiedere talmente tanto tempo da impedire al thread dell’applicazione principale di aggiornare lo schermo abbastanza rapidamente. Ciò può causare una visualizzazione a scatti o un blocco dell’immagine sullo schermo.
L’uso di un worker permette di eseguire un’operazione molto lunga o lenta in background. Ogni worker esegue il proprio codice in un thread di esecuzione separato dagli altri worker. Un worker il cui codice richiede tempi di esecuzione molto lunghi non impedisce l’esecuzione del codice di un altro worker. Al contrario, i due set di codice vengono eseguiti in parallelo. Di conseguenza, un worker può essere utilizzato per eseguire codice in background mentre il thread dell’applicazione principale rimane libero e può continuare ad aggiornare normalmente lo schermo.
Questa capacità di eseguire simultaneamente più set di istruzioni di codice viene definita contemporaneità di esecuzione (in inglese, "concurrency").
Nota: l’uso dei worker per la contemporaneità di esecuzione è supportato in Flash Player e in AIR sulle piattaforme desktop. Per le piattaforme mobili, la contemporaneità di esecuzione è supportata in AIR su Android e iOS. Potete usare la proprietà statica isSupported per verificare se la contemporaneità di esecuzione è supportata prima di utilizzarla.
Non è possibile creare istanze Worker direttamente chiamando la funzione di costruzione Worker()
. Nei contesti che supportano l’uso dei worker per la contemporaneità di esecuzione, all’avvio il runtime crea automaticamente il Worker associato al file SWF principale, denominato worker primordiale.
Ogni worker aggiuntivo viene creato da un SWF separato. Per creare una nuova istanza della classe Worker, passate un ByteArray con i byte del file SWF del worker di background come argomento al metodo createWorker()
della classe WorkerDomain. Sono possibili tre modi diversi per accedere ai byte di un file SWF a questo scopo:
-
Usare il metatag [Embed] per incorporare il file .swf nell’applicazione come 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(); }
-
Caricare un file SWF esterno mediante un 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(); }
-
Usare un singolo SWF sia come worker primordiale che come worker di background:
// 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 } }
I worker vengono eseguiti separatamente l’uno dall’altro e non hanno accesso agli stessi elementi (memoria, variabili e codice). Tuttavia, sono disponibili tre meccanismi per passare messaggi e dati tra istanze Worker differenti:
- Proprietà condivise: ogni worker ha un set interno di valori con nome che possono essere impostati e letti sia dall’interno del worker stesso che da altri worker. Potete impostare un valore usando il metodo
setSharedProperty()
e leggere un valore con il metodogetSharedProperty()
. - MessageChannel: un oggetto MessageChannel consente di inviare messaggi e dati da un worker a un altro su un canale a una sola via. Il codice del worker destinatario può restare in ascolto di un evento per essere notificato quando arriva un messaggio. Per creare un oggetto MessageChannel, utilizzate il metodo
createMessageChannel()
. - ByteArray condivisibile: se la proprietà
shareable
di un oggetto ByteArray ètrue
, la stessa la memoria sottostante viene utilizzata per le istanze di quel ByteArray in tutti i worker. Poiché il codice di più worker può accedere alla memoria condivisa contemporaneamente, il vostro codice deve utilizzare i meccanismi descritti nella descrizione della proprietàByteArray.shareable
in modo da evitare problemi dovuti a modifiche impreviste dei dati.
Varie API del runtime non sono disponibili nel codice eseguito in un worker di background. Si tratta principalmente di API relative ai meccanismi di input e output dell’utente o a elementi del sistema operativo come la gestione delle finestre e del trascinamento. In generale, per qualsiasi API che non è supportata in tutti i contesti, utilizzate le proprietà isSupported
, available
e simili per verificare se l’API è disponibile nel contesto del worker di background prima di tentare di utilizzarla.
Nota: le estensioni native non sono supportate per i worker di background e secondari.
I worker sono utili perché limitano il rischio di riduzione della frequenza fotogrammi causata dal blocco del thread di rendering principale da parte di un altro codice. Tuttavia, i worker richiedono memoria aggiuntiva e risorse della CPU e possono di conseguenza avere un impatto sulle prestazioni generali dell’applicazione. Poiché ogni worker utilizza una propria istanza dalla macchina virtuale del runtime, anche il carico di lavoro di un worker di poca importanza può essere notevole. Quando usate i worker, provate il codice su tutte le piattaforme di destinazione per assicurarvi che il suo consumo delle risorse di sistema non sia eccessivo. Adobe consiglia di non utilizzare più di uno o due worker di background in uno scenario tipico.
Altri esempi
Altre informazioni
Intro to AS3 Workers: Image Processing di Shawn Blais
Multithreaded Physics: Using AS3 Workers for a physics engine di Shawn Blais
Elementi API correlati
Proprietà | Definito da | ||
---|---|---|---|
constructor : Object
Un riferimento all'oggetto classe o alla funzione di costruzione per una determinata istanza di oggetto. | Object | ||
current : Worker [statico] [sola lettura]
Fornisce accesso al worker che contiene il codice corrente.
| Worker | ||
isPrimordial : Boolean [sola lettura]
Indica se questo worker è il worker primordiale. | Worker | ||
isSupported : Boolean [statico] [sola lettura]
Indica se il contesto runtime corrente supporta l’uso degli oggetti Worker per l’esecuzione contemporanea del codice. | Worker | ||
state : String [sola lettura]
Lo stato corrente dell’oggetto worker nel suo ciclo di vita. | Worker |
Metodo | Definito da | ||
---|---|---|---|
addEventListener(type:String, listener:Function, useCapture:Boolean = false, priority:int = 0, useWeakReference:Boolean = false):void [override]
Registra un oggetto listener di eventi con un oggetto EventDispatcher, in modo che il listener riceva la notifica di un evento. | Worker | ||
Crea una nuova istanza MessageChannel per inviare messaggi dal worker sul quale il metodo viene chiamato a un altro worker destinatario. | Worker | ||
Invia un evento nel flusso di eventi. | EventDispatcher | ||
Recupera un valore memorizzato in questo worker con una chiave con nome. | Worker | ||
Verifica se per l'oggetto EventDispatcher sono presenti listener registrati per un tipo specifico di evento. | EventDispatcher | ||
Indica se per un oggetto è definita una proprietà specifica. | Object | ||
Indica se un'istanza della classe Object si trova nella catena di prototipi dell'oggetto specificato come parametro. | Object | ||
Indica se la proprietà specificata esiste ed è enumerabile. | Object | ||
[override]
Rimuove un listener dall'oggetto EventDispatcher. | Worker | ||
Imposta la disponibilità di una proprietà dinamica per le operazioni cicliche. | Object | ||
Fornisce un valore con nome che è disponibile al codice eseguito nell’SWF del worker. | Worker | ||
Avvia l’esecuzione del worker. | Worker | ||
Interrompe l’esecuzione del codice di questo worker. | Worker | ||
Restituisce la rappresentazione in formato stringa di questo oggetto, formattato in base alle convenzioni specifiche per le versioni localizzate. | Object | ||
Restituisce la rappresentazione in formato stringa dell'oggetto specificato. | Object | ||
Restituisce il valore di base dell'oggetto specificato. | Object | ||
Verifica se un listener di eventi è registrato con questo oggetto EventDispatcher o qualsiasi suo antenato per il tipo di evento specificato. | EventDispatcher |
Evento | Riepilogo | Definito da | ||
---|---|---|---|---|
[evento di trasmissione] Inviato quando Flash Player o l'applicazione AIR ottiene lo stato di attivazione del sistema operativo ed entra nello stato attivo. | EventDispatcher | |||
[evento di trasmissione] Inviato quando Flash Player o l'applicazione AIR perde l'attivazione del sistema operativo e sta entrando nello stato inattivo. | EventDispatcher | |||
Inviato quando cambia il valore della proprietà state del worker. | Worker |
current | proprietà |
isPrimordial | proprietà |
isPrimordial:Boolean
[sola lettura] Versione linguaggio: | ActionScript 3.0 |
Versioni runtime: | Flash Player 11.4, AIR 3.4 |
Indica se questo worker è il worker primordiale.
Il worker primordiale è il worker in cui viene eseguito l’SWF iniziale. Questo worker controlla il rendering sullo schermo.
Questa proprietà può essere utilizzata per realizzare un’applicazione in cui il worker primordiale e quello di background sono due istanze dello stesso file SWF. L’alternative è quella di strutturare il codice in modo tale che il worker di background utilizzi un codice differente compilato in un SWF diverso rispetto al worker primordiale.
Implementazione
public function get isPrimordial():Boolean
isSupported | proprietà |
isSupported:Boolean
[sola lettura] Versione linguaggio: | ActionScript 3.0 |
Versioni runtime: | Flash Player 11.4, AIR 3.4 |
Indica se il contesto runtime corrente supporta l’uso degli oggetti Worker per l’esecuzione contemporanea del codice.
Se la contemporaneità di esecuzione è disponibile, il valore di questa proprietà + true
.
Implementazione
public static function get isSupported():Boolean
state | proprietà |
state:String
[sola lettura] Versione linguaggio: | ActionScript 3.0 |
Versioni runtime: | Flash Player 11.4, AIR 3.4 |
Lo stato corrente dell’oggetto worker nel suo ciclo di vita. I valori possibili per questa proprietà sono definiti nella classe WorkerState.
Implementazione
public function get state():String
Elementi API correlati
addEventListener | () | metodo |
override public function addEventListener(type:String, listener:Function, useCapture:Boolean = false, priority:int = 0, useWeakReference:Boolean = false):void
Versione linguaggio: | ActionScript 3.0 |
Versioni runtime: | Flash Player 11.4, AIR 3.4 |
Registra un oggetto listener di eventi con un oggetto EventDispatcher, in modo che il listener riceva la notifica di un evento. Potete registrare listener di eventi in tutti i nodi dell'elenco di visualizzazione per un tipo di evento, una fase e una priorità specifiche.
Una volta registrato un listener di eventi, non potete modificarne la priorità mediante chiamate aggiuntive a addEventListener()
. Per modificare la priorità di un listener dovete chiamare innanzitutto removeListener()
. In seguito potete registrare nuovamente il listener con il nuovo livello di priorità.
Tenete presente che, dopo la registrazione del listener, le successive chiamate a addEventListener()
con un valore type
o useCapture
diverso determinano la creazione di un'altra registrazione per il listener. Ad esempio, se registrate un listener inizialmente con useCapture
impostato su true
, l'intercettazione avviene solo durante la fase di cattura. Se chiamate di nuovo addEventListener()
utilizzando lo stesso oggetto listener ma impostando useCapture
su false
, ottenete due listener separati: uno rileva gli eventi durante la fase di cattura e l'altro durante la fasi target e di bubbling.
Non potete registrare un listener di eventi solo per la fase target o per la fase di bubbling. Queste fasi vengono accoppiate durante la registrazione perché la propagazione è valida solo per gli antenati del nodo target.
Se il listener di eventi non è più necessario, rimovetelo con una chiamata a removeEventListener()
per evitare problemi di memoria. I listener di eventi non vengono eliminati automaticamente dalla memoria perché il garbage collector non rimuove il listener fintantoché esiste l'oggetto che effettua l'invio (a meno che il parametro useWeakReference
non sia impostato su true
).
Se copiate un'istanza EventDispatcher, i listener di eventi associati all'istanza non vengono copiati (se un nodo appena creato necessita di un listener di eventi, dovete associarlo dopo avere creato il nodo). Se invece spostate un'istanza EventDispatcher, insieme a questa vengono spostati anche i listener di eventi associati.
Se il listener di eventi viene registrato su un nodo mentre questo sta elaborando un evento, il listener di eventi non viene attivato durante la fase corrente ma può esserlo durante una fase successiva del flusso di eventi, ad esempio la fase di bubbling.
Se un listener di eventi viene rimosso da un nodo mentre questo sta elaborando un evento, il listener continua a essere attivato dalle azioni in corso. Dopo che è stato rimosso, il listener di eventi non viene più richiamato (a meno che non venga registrato nuovamente per elaborazioni future).
Parametri
type:String — Il tipo di evento.
| |
listener:Function — La funzione listener che elabora l'evento. Questa funzione deve accettare un oggetto Event come unico parametro e non restituire alcun valore, come mostra l'esempio che segue:
function(evt:Event):void La funzione può avere qualunque nome. | |
useCapture:Boolean (default = false ) —
Determina se il listener funziona nella fase di cattura o nelle fasi target e di bubbling. Se useCapture è impostato su true , il listener elabora l'evento solo durante la fase di cattura e non nella fase target o di bubbling. Se useCapture è impostato su false , il listener elabora l'evento solo durante la fase target o di bubbling. Per consentire l'intercettazione dell'evento in tutte e tre le fasi, chiamate due volte addEventListener , una volta con useCapture impostato su true e un'altra volta con useCapture impostato su false .
| |
priority:int (default = 0 ) — Il livello di priorità del listener di eventi. La priorità è indicata da un numero intero a 32 bit con segno. Più alto è il numero, più alta è la priorità. Tutti i listener con priorità n vengono elaborati prima dei listener con priorità n-1. Se due o più listener hanno la stessa priorità, l'elaborazione avviene secondo l'ordine in cui sono stati aggiunti. La priorità predefinita è 0.
| |
useWeakReference:Boolean (default = false ) — Determina se il riferimento al listener è forte o debole. Un riferimento forte (predefinito) evita che il listener venga sottoposto al processo di garbage collection, un riferimento debole no. Le funzioni dei membri a livello di classe non sono soggette a garbage collection, pertanto è possibile impostare |
createMessageChannel | () | metodo |
public function createMessageChannel(receiver:Worker):MessageChannel
Versione linguaggio: | ActionScript 3.0 |
Versioni runtime: | Flash Player 11.4, AIR 3.4 |
Crea una nuova istanza MessageChannel per inviare messaggi dal worker sul quale il metodo viene chiamato a un altro worker destinatario. Il codice del worker che crea l’oggetto MessageChannel può utilizzarlo per inviare messaggi a una sola via all’oggetto Worker specificato nell’argomento receiver
.
Anche se un’istanza MessageChannel può essere utilizzata per inviare messaggi e dati da un’istanza Worker a un’altra, almeno un’istanza MessageChannel deve essere passata a un Worker di livello inferiore come proprietà condivisa, chiamando il metodo setSharedProperty()
dell’oggetto 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);
Parametri
receiver:Worker — Il worker che riceverà i messaggi trasmessi dal canale di messaggio creato.
|
MessageChannel — L’oggetto MessageChannel creato dall’operazione.
|
getSharedProperty | () | metodo |
public function getSharedProperty(key:String):*
Versione linguaggio: | ActionScript 3.0 |
Versioni runtime: | Flash Player 11.4, AIR 3.4 |
Recupera un valore memorizzato in questo worker con una chiave con nome.
Il codice di un worker di livello inferiore può chiamare questo metodo per recuperare un valore già nella funzione di costruzione della classe principale dell’SWF del worker.
Parametri
key:String — Il nome della proprietà condivisa da recuperare.
|
* — Il valore della proprietà condivisa memorizzato con la chiave specificata, oppure null se non è memorizzato alcun valore per la chiave specificata.
|
removeEventListener | () | metodo |
override public function removeEventListener(type:String, listener:Function, useCapture:Boolean = false):void
Versione linguaggio: | ActionScript 3.0 |
Versioni runtime: | Flash Player 11.4, AIR 3.4 |
Rimuove un listener dall'oggetto EventDispatcher. Se non esiste un listener corrispondente registrato nell'oggetto EventDispatcher, la chiamata a questo metodo non ha alcun effetto.
Parametri
type:String — Il tipo di evento.
| |
listener:Function — L'oggetto listener da rimuovere.
| |
useCapture:Boolean (default = false ) —
Specifica se il listener è stato registrato per la fase di cattura o per le fasi target e di bubbling. Se il listener è stato registrato sia per la fase di cattura che per quelle target e di bubbling, per eliminarle entrambe sono necessarie due chiamate a removeEventListener() , una con useCapture() impostato su true e un'altra con useCapture() impostato su false .
|
setSharedProperty | () | metodo |
public function setSharedProperty(key:String, value:*):void
Versione linguaggio: | ActionScript 3.0 |
Versioni runtime: | Flash Player 11.4, AIR 3.4 |
Fornisce un valore con nome che è disponibile al codice eseguito nell’SWF del worker.
Potete chiamare questo metodo prima di chiamare il metodo start()
del worker. In tal caso, la proprietà condivisa è disponibile al codice dell’SWF del worker in fase di costruzione.
Il valore passato al parametro value
può essere quasi qualsiasi oggetto. Salvo le eccezioni indicate di seguito, qualunque oggetto passato al parametro value
non viene passato mediante un riferimento. Le modifiche apportate all’oggetto in un worker dopo la chiamata setSharedProperty()
non vengono applicate all’altro worker. L’oggetto viene copiato serializzandolo in formato AMF3 e deserializzandolo in un nuovo oggetto nel worker destinatario. Per questo motivo, qualsiasi oggetto che non può essere serializzato nel formato AMF3, compresi gli oggetti di visualizzazione, non può essere passato al parametro value
. Affinché una classe personalizzata possa essere passata correttamente, la definizione della classe deve essere registrata utilizzando la funzione flash.net.registerClassAlias()
o il metadato [RemoteClass]
. In ambedue i casi occorre utilizzare lo stesso alias per entrambe le versioni della classe destinate ai due worker.
Cinque tipi di oggetti rappresentano eccezioni alla regola che prevede che gli oggetti non possano essere condivisi tra i worker:
- Il worker
- MessageChannel
- ByteArray condivisibile (un oggetto ByteArray con la proprietà
shareable
impostata sutrue
). - Mutex
- Condition
Se si passa un’istanza di questi oggetti al parametro value
, ogni worker ha un riferimento allo stesso oggetto sottostante. Le modifiche apportate a un’istanza in un worker sono immediatamente disponibili negli altri worker. Inoltre, se passate la stessa istanza di questi oggetti più di una volta utilizzando setSharedProperty()
, il runtime non crea una nuova copia dell’oggetto nel worker destinatario. Viene invece riutilizzato lo stesso riferimento, riducendo così il consumo di memoria.
Se si chiama questo metodo con null
o undefined
per l’argomento value
, viene cancellato qualsiasi valore precedentemente impostato per l’argomento key
specificato. La cancellazione di un valore eseguita in questo modo rimuove il riferimento al valore, rendendolo disponibile per il processo di garbage collection.
Potete usare qualsiasi valore String nell’argomento key. Queste proprietà condivise sono disponibili a qualsiasi codice che ha accesso al worker. Per evitare di sovrascrivere un valore involontariamente, valutate l’uso di un prefisso, un suffisso o un meccanismo simile per tentare di rendere univoci i nomi delle chiavi.
Parametri
key:String — Il nome con il quale è memorizzata la proprietà condivisa.
| |
value:* — Il valore della proprietà condivisa.
|
Elementi API correlati
start | () | metodo |
public function start():void
Versione linguaggio: | ActionScript 3.0 |
Versioni runtime: | Flash Player 11.4, AIR 3.4 |
Avvia l’esecuzione del worker. Il runtime crea il thread del worker e chiama la funzione di costruzione della classe principale dell’SWF del worker.
L’operazione è asincrona. Una volta che l’avvio del worker è completo, il worker cambia la propria proprietà state
in WorkerState.RUNNING
e invia un evento workerState
.
terminate | () | metodo |
public function terminate():Boolean
Versione linguaggio: | ActionScript 3.0 |
Versioni runtime: | Flash Player 11.4, AIR 3.4 |
Interrompe l’esecuzione del codice di questo worker. Una chiamata di questo metodo interrompe il codice ActionScript eventualmente in esecuzione nell’SWF del worker.
RestituisceBoolean — true se il codice del worker era in esecuzione ed è stato interrotto, oppure false se il worker non era stato avviato.
|
workerState | Evento |
flash.events.Event
proprietà Event.type =
flash.events.Event.WORKER_STATE
Versione linguaggio: | ActionScript 3.0 |
Versioni runtime: | Flash Player 11.4, AIR 3.4 |
Inviato quando cambia il valore della proprietà state
del worker.
Event.WORKER_STATE
definisce il valore della proprietà type
di un oggetto evento workerState
.
Questo evento ha le seguenti proprietà:
Proprietà | Valore |
---|---|
bubbles | false |
cancelable | false ; non è presente alcun comportamento predefinito da annullare. |
currentTarget | L'oggetto che elabora attivamente l'oggetto Event con un listener di eventi. |
target | L'oggetto che ha inviato l'evento. |
L’esempio consiste di tre classi ActionScript: WorkerExample è la classe principale e il worker di livello superiore. BackgroundWorker è la classe che esegue il lavoro di background. È compilata come classe principale dell’SWF del worker di background. CountResult è una classe personalizzata che viene utilizzata per passare dati tra i due worker come oggetto singolo anziché con valori multipli.
In questo esempio, il worker di background esegue un conteggio in una ripetizione ciclica fino al numero specificato dal worker principale. Man mano che procede nell’esecuzione di questa operazione, invia messaggi di avanzamento al worker principale. Infine, quando il conteggio giunge al termine, il worker di background invia un messaggio al worker principale per notificare il completamento dell’operazione e il tempo totale trascorso.
La classe WorkerExample è la classe principale dell’SWF, quindi è anche la classe principale del worker primordiale. Nel metodo initialize()
, il codice crea l’oggetto worker di background utilizzando i byte della classe BackgroundWorker, che sono incorporati in un tag [Embed]
.
Dopo aver creato il worker di background chiamando WorkerDomain.createWorker()
, il codice abilita la comunicazione tra i worker. Innanzi tutto il codice crea un set di oggetti MessageChannel. Quindi li passa al worker di background chiamando il metodo setSharedProperty()
. Infine esegue la registrazione per l’evento workerState
dell’oggetto Worker di background e avvia il worker chiamandone il metodo start()
.
Man mano che procede nell’esecuzione dell’operazione, il worker di background invia messaggi di avanzamento (e infine di completamento) al worker principale. Quest’ultimo usa le informazioni ricevute per aggiornare la barra di avanzamento e l’indicatore di testo.
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; } } }
Nel metodo initialize()
, riceve gli oggetti MessageChannel passati dal worker principale. Questi oggetti vengono utilizzati per la comunicazione tra i due worker.
Il worker principale chiama il metodo send()
sul canale di messaggio commandChannel
per inviare un messaggio. Nel worker di background, il runtime quindi invia l’evento channelMessage
chiamando il metodo handleCommandMessage()
.
Il lavoro vero e proprio del worker di background ha luogo nel metodo count()
. Man mano che il worker di background procede nel conteggio, invia messaggi di avanzamento al worker principale chiamando il metodo send()
sull’oggetto MessageChannel progressChannel
. Quando termina il conteggio, il worker chiama il metodo send()
sull’oggetto MessageChannel resultChannel
.
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()
utilizzando lo stesso nome di alias.
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. Poiché il caricamento dinamico di un file SWF remoto contenente il codice ActionScript non funziona, è necessario passare il file SWF remoto al worker come SWF stripped. 2. L’incorporamento di SWF (con codice ABC) mediante tag [Embed] non funzionerà in iOS. Ogni worker aggiuntivo viene creato da un SWF separato. Per creare una nuova istanza della classe Worker, passate un ByteArray con i byte del file SWF del worker di background come argomento al metodo createWorker()
della classe di WorkerDomain.
Esistono due metodi comuni per accedere ai byte di un SWF a questo scopo su iOS: il primo modo è quello di utilizzare Loader
per caricare un file SWF esterno e il secondo è utilizzare URLLoader
per caricare il file SWF.
L’esempio seguente utilizza l’API Loader
per caricare il file 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
, è necessario un controllo di proprietà isPrimordial
nel worker di background, come mostrato nell’esempio.
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, 02:44 PM Z