패키지 | flash.system |
클래스 | public final class Worker |
상속 | Worker EventDispatcher Object |
언어 버전: | ActionScript 3.0 |
런타임 버전: | Flash Player 11.4, AIR 3.4 |
워커를 사용하면 다른 워커(기본 swf의 워커 포함)에서 다른 작업이 실행 중인 동안 "백그라운드"에서 코드를 실행할 수 있습니다. 워커가 아닌 컨텍스트의 경우 대규모 데이터 집합을 처리하는 등의 일부 작업은 실행 시간이 지나치게 오래 걸리므로 기본 응용 프로그램 스레드가 화면을 신속하게 업데이트하지 못하게 됩니다. 이로 인해 화면의 표시가 자연스럽지 못하거나 작동이 멈출 수 있습니다.
워커를 사용하면 오랫동안 실행하거나 속도가 느린 작업을 백그라운드에서 수행할 수 있습니다. 각각의 워커는 다른 워커의 별도의 실행 스레드에서 해당 코드를 실행합니다. 특정 워커에서 오랫동안 실행되는 코드가 있더라도 다른 워커의 코드가 실행되지 못하도록 방해하지는 않습니다. 대신 2개의 코드 집합이 동시에 실행됩니다. 따라서 기본 응용 프로그램 스레드에서 계속해서 자유롭게 화면을 업데이트하는 동안 워커를 사용하여 코드를 백그라운드에서 실행할 수 있습니다.
이처럼 여러 개의 코드 명령 집합을 동시에 실행하는 기능을 동시성이라고 합니다.
참고: 동시성을 위해 워커를 사용하는 것은 데스크톱 플랫폼의 Flash Player와 AIR에서 모두 지원됩니다. 모바일 플랫폼의 경우 Android와 iOS 모두의 AIR에서 동시성이 지원됩니다. 동시성을 사용하기 전에 정적 isSupported 속성을 활용하여 동시성 지원 여부를 확인할 수 있습니다.
Worker()
생성자를 호출하여 Worker 인스턴스를 직접 만들 필요는 없습니다. 동시성을 위해 워커를 사용할 수 있는 컨텍스트에서는 시작 시 런타임이 최초 워커라고 하는 기본 SWF와 연관된 워커를 자동으로 생성합니다.
각각의 추가 워커는 별개의 SWF에서 만들어집니다. 새 Worker 클래스 인스턴스를 생성하려면 백그라운드 워커의 swf 바이트를 인수로 사용하여 ByteArray를 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를 최초 워커 및 백그라운드 워커로 모두 사용합니다.
// 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 인스턴스 간에 메시지 및 데이터를 전달하는 데 사용할 수 있는 세 가지 메커니즘이 있습니다.
- 공유 속성: 각각의 워커 내부에는 워커 자체에서는 물론 워커 상호 간에 읽어오고 설정할 수 있는 명명된 값 집합이 있습니다. 값을 설정하려면
setSharedProperty()
메서드를 사용하고 값을 읽으려면getSharedProperty()
메서드를 사용하면 됩니다. - MessageChannel: MessageChannel 객체를 사용하면 워커 상호 간에 단방향 메시지 및 데이터를 전송할 수 있습니다. 수신 워커의 코드는 메시지 도착 시기를 알리는 이벤트를 수신할 수 있습니다. MessageChannel 객체를 생성하려면
createMessageChannel()
메서드를 사용합니다. - 공유 가능 ByteArray: ByteArray 객체의
shareable
속성이true
인 경우에는 모든 워커의 해당 ByteArray 인스턴스에 대해 동일한 기본 메모리가 사용됩니다. 여러 워커의 코드가 공유 메모리에 동시에 액세스할 수 있으므로 해당 코드에서는ByteArray.shareable
속성 설명에 나와 있는 메커니즘을 사용하여 예기치 않은 데이터 변경으로 인한 문제를 방지해야 합니다.
백그라운드 워커에서 실행 중인 코드에서는 여러 개의 런타임 API를 사용할 수 없습니다. 이는 주로 사용자 입력 및 출력 메커니즘이나 창 및 끌기 같은 운영 체제 요소와 관련된 API로 구성되어 있습니다. 일반적으로 특정 컨텍스트에서 지원되지 않는 API의 경우에는 isSupported
, available
를 비롯해 이와 비슷한 속성을 사용하여 API를 사용하기 전에 백그라운드 워커 컨텍스트에서 API를 사용할 수 있는지 여부를 확인합니다.
참고: 백그라운드 및 보조 작업자에 대해서는 기본 확장이 지원되지 않습니다.
프레임 속도는 기본 렌더링 스레드가 다른 코드에 의해 차단될 때 감소할 수 있으며, 워커를 사용하면 이러한 문제를 최소화할 수 있습니다. 그러나 워커는 시스템 메모리 및 CPU를 추가로 점유하며 이는 곧 전반적인 응용 프로그램 성능의 저하로 이어질 수 있습니다. 각 워커에서는 자체의 런타임 가상 머신 인스턴스를 사용하므로 작은 워커도 큰 오버헤드를 일으킬 수 있습니다. 워커를 사용할 경우 모든 대상 플랫폼에서 해당 코드를 테스트하여 시스템에 추가되는 부담이 너무 크지 않은지 확인해야 합니다. 일반적인 상황에서 백그라운드 워커는 3개 이상 사용하지 않는 것이 좋습니다.
추가 정보
AS3 워커 소개: 이미지 처리(작성: Shawn Blais)
멀티 스레드 물리학: 물리학 엔진에 AS3 워커 사용(작성: Shawn Blais)
관련 API 요소
속성 | 정의 주체 | ||
---|---|---|---|
constructor : Object
지정된 객체 인스턴스의 클래스 객체 또는 생성자 함수에 대한 참조입니다. | Object | ||
current : Worker [정적] [읽기 전용]
현재 코드가 포함된 워커에 액세스할 수 있도록 합니다.
| Worker | ||
isPrimordial : Boolean [읽기 전용]
이 워커가 최초 워커인지 여부를 나타냅니다. | Worker | ||
isSupported : Boolean [정적] [읽기 전용]
현재 런타임 컨텍스트에서 동시 코드 실행을 위해 Worker 객체의 사용을 지원하는지 여부를 나타냅니다. | Worker | ||
state : String [읽기 전용]
해당 수명 주기에서 워커의 현재 상태입니다. | Worker |
메서드 | 정의 주체 | ||
---|---|---|---|
addEventListener(type:String, listener:Function, useCapture:Boolean = false, priority:int = 0, useWeakReference:Boolean = false):void [재정의]
리스너에서 이벤트 알림을 받을 수 있도록 EventDispatcher 객체에 이벤트 리스너 객체를 등록합니다. | Worker | ||
새 MessageChannel 인스턴스를 생성하여 메서드가 호출되는 워커에서 다른 수신자 워커로 메시지를 전송합니다. | Worker | ||
이벤트를 이벤트 흐름으로 전달합니다. | EventDispatcher | ||
명명된 키를 사용하여 이 워커에 저장된 값을 검색합니다. | Worker | ||
EventDispatcher 객체에 특정 유형의 이벤트에 대한 리스너가 등록되어 있는지 여부를 확인합니다. | EventDispatcher | ||
지정된 속성이 객체에 정의되어 있는지 여부를 나타냅니다. | Object | ||
Object 클래스의 인스턴스가 매개 변수로 지정된 객체의 프로토타입 체인에 있는지 여부를 나타냅니다. | Object | ||
지정된 속성이 존재하고 열거 가능한지 여부를 나타냅니다. | Object | ||
[재정의]
EventDispatcher 객체에서 리스너를 제거합니다. | Worker | ||
루프 작업에서 동적 속성을 사용할 수 있는지 여부를 설정합니다. | Object | ||
워커의 swf에서 실행되는 코드에 사용할 수 있는 명명된 값을 제공합니다. | Worker | ||
워커의 실행을 시작합니다. | Worker | ||
이 워커의 코드 실행을 중지합니다. | Worker | ||
로캘별 규칙에 따라 서식이 지정된 이 객체의 문자열 표현을 반환합니다. | Object | ||
지정된 객체의 문자열 표현을 반환합니다. | Object | ||
지정된 객체의 프리미티브 값을 반환합니다. | Object | ||
이 EventDispatcher 객체 또는 조상 객체에 지정한 이벤트 유형에 대한 이벤트 리스너가 등록되어 있는지 여부를 확인합니다. | EventDispatcher |
이벤트 | 요약 | 정의 주체 | ||
---|---|---|---|---|
[브로드캐스트 이벤트] Flash Player 또는 AIR 응용 프로그램이 운영 체제 포커스를 얻어 활성화될 때 전달됩니다. | EventDispatcher | |||
[브로드캐스트 이벤트] Flash Player 또는 AIR 응용 프로그램이 운영 체제 포커스를 잃고 비활성화될 때 전달됩니다. | EventDispatcher | |||
워커의 state 속성 값이 변경되는 경우 전달됩니다. | Worker |
current | 속성 |
isPrimordial | 속성 |
isPrimordial:Boolean
[읽기 전용] 언어 버전: | ActionScript 3.0 |
런타임 버전: | Flash Player 11.4, AIR 3.4 |
이 워커가 최초 워커인지 여부를 나타냅니다.
최초 워커는 초기 swf가 실행 중인 워커입니다. 이 워커는 화면에 대한 렌더링을 제어합니다.
이 속성은 최초 워커와 백그라운드 워커가 동일한 swf 파일의 두 인스턴스인 응용 프로그램을 설계하는 데 사용할 수 있습니다. 이에 대한 대안으로 백그라운드 워커가 최초 워커와 다른 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
로 설정된 리스너를 등록하면 이 리스너는 캡처 단계 동안에만 수신합니다. 그러나 useCapture
를 false
로 설정하고 동일한 리스너 객체를 사용하여 addEventListener()
를 다시 호출하면 별도로 두 개의 리스너가 등록되어, 한 리스너는 캡처 단계 동안 수신하고 다른 하나는 대상 및 버블링 단계 동안 수신합니다.
대상 단계 또는 버블링 단계 전용의 이벤트 리스너를 등록할 수는 없습니다. 버블링은 대상 노드의 조상에만 적용되기 때문에 이들 단계는 등록 과정에서 하나로 통합됩니다.
사용하지 않는 이벤트 리스너는 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 인스턴스를 생성하여 메서드가 호출되는 워커에서 다른 수신자 워커로 메시지를 전송합니다. MessageChannel 객체를 생성하는 워커의 코드에서는 이 객체를 사용하여 receiver
인수로 지정된 Worker 객체로 단방향 메시지를 전송합니다.
MessageChannel 인스턴스를 사용하여 Worker 인스턴스 간에 메시지와 데이터를 전송할 수 있지만 Worker 객체의 setSharedProperty()
메서드를 사용하여 하나 이상의 MessageChannel 인스턴스를 자식 워커에 공유 속성으로 전달해야 합니다.
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 — 생성된 메시지 채널을 통해 전송되는 메시지를 수신할 워커
|
MessageChannel — 작업을 통해 생성된 MessageChannel 객체
|
getSharedProperty | () | 메서드 |
public function getSharedProperty(key:String):*
언어 버전: | ActionScript 3.0 |
런타임 버전: | Flash Player 11.4, AIR 3.4 |
명명된 키를 사용하여 이 워커에 저장된 값을 검색합니다.
자식 워커의 코드는 이 메서드를 사용하여 워커 swf의 기본 클래스에서 가능한 한 빨리 값을 검색할 수 있습니다.
매개 변수
key:String — 검색할 공유 속성의 이름입니다.
|
* — 지정된 키를 사용하여 저장된 공유 속성 값이거나, 지정된 키에 대해 저장된 값이 없는 경우에는 null 입니다.
|
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 |
워커의 swf에서 실행되는 코드에 사용할 수 있는 명명된 값을 제공합니다.
이 메서드는 워커의 start()
메서드보다 먼저 호출할 수 있습니다. 이 경우 공유 속성은 생성 시에 워커 swf의 코드에 사용할 수 있습니다.
value
매개 변수로 전달되는 값은 거의 모든 객체일 수 있습니다. 아래 설명된 예외를 제외하고 value
매개 변수로 전달되는 모든 객체는 참조에 의해 전달되지 않습니다. setSharedProperty()
가 호출된 후 특정 워커의 객체에서 변경된 사항은 다른 워커로 전달되지 않습니다. 객체는 AMF3 형식으로 직렬화하고 수신 워커에서 새 객체로 직렬화를 해제하는 방식으로 복사됩니다. 이 때문에 표시 객체를 비롯해 AMF3 형식으로 직렬화할 수 없는 객체는 value
매개 변수로 전달할 수 없습니다. 사용자 정의 클래스를 올바르게 전달하려면 flash.net.registerClassAlias()
함수 또는 [RemoteClass]
메타데이터를 사용하여 클래스 정의를 등록해야 합니다. 어느 쪽 방법을 사용하든 클래스의 두 워커 버전 모두에 대해 동일한 별칭을 사용해야 합니다.
객체가 워커 간에 공유되지 않는 규칙의 예외에 해당하는 객체의 유형에는 다섯 가지가 있습니다.
- 작업자가
- MessageChannel
- 공유 가능 ByteArray(해당
shareable
속성이true
로 설정된 ByteArray 객체) - Mutex
- Condition
이러한 객체의 인스턴스를 value
매개 변수로 전달하는 경우 각각의 워커는 동일한 기본 객체를 참조합니다. 한 워커에 있는 인스턴스에서 변경된 내용은 다른 워커에서 즉시 사용 가능합니다. 또한 setSharedProperty()
를 사용하여 이러한 객체의 동일한 인스턴스를 두 번 이상 전달하는 경우 런타임은 수신 워커에 해당 객체의 새 복사본을 만들지 않습니다. 대신 동일한 참조가 다시 사용되므로 시스템 메모리 사용량이 줄어듭니다.
value
인수에 대해 null
또는 undefined
를 지정하여 이 메서드를 호출하면 지정된 key
인수에 대해 이전에 설정한 값이 모두 지워집니다. 이러한 방법으로 값을 지우면 값에 대한 참조가 제거되어 해당 값을 가비지 수집할 수 있습니다.
key 인수에는 모든 문자열 값을 사용할 수 있습니다. 이러한 공유 속성은 워커에 액세스할 수 있는 모든 코드에서 사용할 수 있습니다. 의도치 않게 값을 덮어쓰지 않도록 하려면 접두어, 접미어 또는 이와 유사한 메커니즘을 사용하여 키 이름을 고유하게 만드는 것이 좋습니다.
매개 변수
key:String — 공유 속성을 저장하는 데 사용되는 이름입니다.
| |
value:* — 공유 속성의 값입니다.
|
관련 API 요소
start | () | 메서드 |
public function start():void
언어 버전: | ActionScript 3.0 |
런타임 버전: | Flash Player 11.4, AIR 3.4 |
워커의 실행을 시작합니다. 런타임은 워커 스레드를 만들고 워커 swf 기본 클래스의 생성자를 호출합니다.
이 작업은 비동기식으로 수행됩니다. 작업 시작이 완료되면 해당 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 |
워커의 state
속성 값이 변경되는 경우 전달됩니다.
Event.WORKER_STATE
상수는 workerState
이벤트 객체의 type
속성 값을 정의합니다.
이 이벤트에는 다음과 같은 속성이 있습니다.
속성 | 값 |
---|---|
bubbles | false |
cancelable | false . 취소할 기본 비헤이비어가 없습니다. |
currentTarget | 이벤트 리스너를 통해 Event 객체를 처리하고 있는 객체입니다. |
target | 이벤트를 전달한 객체입니다. |
이 예제는 3개의 ActionScript 클래스로 구성되어 있습니다. 먼저, WorkerExample은 기본 클래스이자 부모 워커입니다. BackgroundWorker는 백그라운드 작업을 수행하는 클래스로, 백그라운드 워커 swf의 기본 클래스로 컴파일됩니다. CountResult는 두 워커 간에 여러 개의 값이 아닌 단일 객체로 데이터를 전달하는 데 사용되는 맞춤형 클래스입니다.
이 예제에서 백그라운드 워커는 부모 워커에 지정된 수까지 반복해서 계산됩니다. 해당 작업에서 작업을 진행함에 따라 진행률 메시지를 부모 워커로 전송합니다. 마지막으로 계산이 끝나면 백그라운드 워커는 계산 완료 사실과 계산에 소요된 시간을 알려 주는 메시지를 부모 워커로 전송합니다.
WorkerExample 클래스는 swf의 기본 클래스이므로 최초 워커의 기본 클래스이기도 합니다. initialize()
메서드에서 코드는 [Embed]
태그를 통해 포함되는 BackgroundWorker 클래스의 바이트를 사용하여 백그라운드 워커 객체를 생성합니다.
코드에서는 WorkerDomain.createWorker()
를 호출하여 백그라운드 워커를 생성한 후 워커 간에 통신을 설정합니다. 먼저, 코드에서는 MessageChannel 객체 집합을 생성합니다. 그런 다음 해당 setSharedProperty()
메서드를 호출하여 이 객체 집합을 백그라운드 워커로 전달합니다. 마지막으로 백그라운드 Worker 객체의 workerState
이벤트에 등록하고, 해당 start()
메서드를 호출하여 워커를 시작합니다.
백그라운드 워커는 해당 작업을 수행하면서 부모 워커로 진행률(이후에는 결과까지) 메시지를 전송합니다. 부모 워커는 이 정보를 사용하여 진행률 표시줄 및 텍스트 표시기를 업데이트합니다.
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()
메서드에서는 부모 워커가 전달하는 MessageChannel 객체를 수신합니다. 이러한 객체는 두 워커 간의 통신에 사용됩니다.
부모 워커는 commandChannel
메시지 채널에서 send()
메서드를 호출하여 메시지를 전송합니다. 그러면 런타임은 백그라운드 워커 내부에서 handleCommandMessage()
메서드를 호출하여 channelMessage
이벤트를 전달합니다.
백그라운드 워커의 실제 작업은 count()
메서드에서 수행됩니다. 백그라운드 워커는 계산을 수행하면서 progressChannel
MessageChannel 객체에서 send()
메서드를 호출하여 부모 워커로 진행률 메시지를 전송합니다. 계산이 완료되면 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로 워커에 전달되어야 합니다. 2. [Embed] 태그를 사용한 SWF 포함(ABC 코드 포함)은 iOS에서 작동하지 않습니다. 각각의 추가 워커는 별개의 SWF에서 만들어집니다. 새 Worker 클래스 인스턴스를 만들려면 백그라운드 워커의 SWF 바이트를 인수로 사용하여 ByteArray를 WorkerDomain 클래스의 createWorker()
메서드로 전달합니다.
iOS에서 이를 위해 SWF의 바이트에 액세스하는 2가지 일반적인 방법이 있습니다. 첫 번째 방법은 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
의 로드 함수가 호출되는 동안 코드가 실행되므로 이 예제에서처럼 백그라운드 워커에 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, 03:17 PM Z