Search code examples
actionscript-3airworkerflash-cc

Worker not receiving messages after RUNNING state, but it does later


Update: Apparently, it's some kind of timing issue. In the code below I create the worker from a click handler, but if I create the worker from the Main constructor (as the doc example does), the commandChannel message gets to the worker -- even though in either case I'm doing the exact same thing: create the worker, listen for RUNNING state, then send message over commandChannel. But that first message only gets through if I create the worker from the Main constructor, while messages later in time (some undetermined timed after RUNNING) always get through. Why? If I can't rely on WorkerState.RUNNING to know when I can send messages to the worker, how can I know when the worker is ready to receive messages?


I basically have the exact same thing as the documentation example, but it's not working. My setup is:

  • Flash Pro CC
  • AIR 17 for Desktop
  • Windows 7

The problem is that the worker does not seem to receive messages through the incoming message channel, though it can successfully send messages to the main SWF through an outgoing message channel.

This is my main class:

public class Main extends MovieClip {

    [Embed(source="TestWorker.swf", mimeType="application/octet-stream")]
    private var WorkerSWF:Class;
    private var workerBytes:ByteArray;

    private var worker:Worker;
    private var commandChannel:MessageChannel;
    private var resultChannel:MessageChannel;

    public function Main() {
        workerBytes = new WorkerSWF();
        stage.addEventListener(MouseEvent.CLICK, clickHandler);
    }

    private function clickHandler(e:MouseEvent):void {
        stage.removeEventListener(MouseEvent.CLICK, clickHandler);
        startWorker();
    }

    private function startWorker():void {
        trace("Start worker");

        worker = WorkerDomain.current.createWorker(workerBytes, true);

        commandChannel = Worker.current.createMessageChannel(worker);
        worker.setSharedProperty("commands", commandChannel);

        resultChannel = worker.createMessageChannel(Worker.current);
        resultChannel.addEventListener(Event.CHANNEL_MESSAGE, resultMessageHandler);
        worker.setSharedProperty("results", resultChannel);

        worker.addEventListener(Event.WORKER_STATE, workerStateHandler);
        worker.start();
    }

    private function workerStateHandler(e:Event):void {
        trace("Worker state:", worker.state);

        if(worker.state == WorkerState.RUNNING) {
            trace("Worker running");
            commandChannel.send("START PLEASE");
        }
    }

    private function resultMessageHandler(e:Event):void {
        trace(e, resultChannel.receive())
    }
}

And my worker SWF class:

public class TestWorker extends Sprite {

    private var commandChannel:MessageChannel;
    private var resultChannel:MessageChannel;

    public function TestWorker () {
        trace("isPrimordial:", Worker.current.isPrimordial)

        commandChannel = Worker.current.getSharedProperty("commands") as MessageChannel;
        commandChannel.addEventListener(Event.CHANNEL_MESSAGE, commandMessageHandler);

        resultChannel = Worker.current.getSharedProperty("results") as MessageChannel;

        resultChannel.send("Hello from worker");
    }

    private function commandMessageHandler(e:Event):void {
        trace("commandMessageHandler")

        //var message:String = commandChannel.receive();

        resultChannel.send("Whatever.");

        setInterval(respond, 1000);
    }

    private function respond(){
        resultChannel.send("Whatever " + new Date());
    }

}

The problem is that the worker's commandMessageHandler is never triggered. I know this because I never receive the "Whatever" message back to the Main SWF. The "Hello from worker" message does get back to the Main SWF, so it's something specific to the main-to-worker message channel. What's wrong?

Additionally, it seems that neither trace actions or runtime errors from the worker are captured by the main SWF. How does one debug a worker SWF?


Solution

  • This seems to be a known issue (see point 2). WorkerState.RUNNING sometimes gets dispatched before the constructor of the worker has actually run. So in my case, from the click handler, the first message got sent before the constructor of the worker had added the listener to receive it.

    So I'm going with the simple workaround: when the worker loads, send a message to the main thread that says "I'm ready" at the end of the constructor. In the main thread, listen for that instead of RUNNING before sending the intial command.