Flex后台工作人员处理失败的MessageChannel冻结应用程序

时间:2017-09-13 12:25:28

标签: actionscript-3 flash flex air flex4

我有以下场景:我使用MessageChannel与Flex应用程序中的后台工作程序进行通信。由于代码最终将被转换为库,因此它还应该能够处理格式错误的输入(例如,通过在后台工作程序中未注册类别名的通道发送类)。在这种情况下,我想中止工人。我的代码如下:

package
{
    import flash.display.Sprite;
    import flash.events.Event;
    import flash.system.MessageChannel;
    import flash.system.Worker;

    public class BW extends Sprite
    {
        /** Incoming channel */
        private var fromCoordinatorChannel:MessageChannel;

        /** Outgoing channel */
        private var toCoordinatorChannel:MessageChannel;

        public function BW()
        {
            super();
            initChannels();
        }

        /**
         * Get channels from shared property and attach event listener 
         */
        private function initChannels():void {
            // Get channnels from shared property
            fromCoordinatorChannel = Worker.current.getSharedProperty("toWorkerChannel");
            toCoordinatorChannel = Worker.current.getSharedProperty("fromWorkerChannel");

            // Attach event listener for incoming messages
            fromCoordinatorChannel.addEventListener(Event.CHANNEL_MESSAGE, onIncomingMessage);
        }

        /**
         * Event handler for incoming messages on the channel.
         * @param event Event that came in
         */
        private function onIncomingMessage(event:Event):void {
            handleIncoming();   
        }

        /**
         * Get oldest message from channel and handle it 
         */
        private function handleIncoming():void {
            if(fromCoordinatorChannel.messageAvailable) {
                try {
                    var wm:Object = fromCoordinatorChannel.receive(true);
                } catch(e:Error) {
                    fromCoordinatorChannel.close();
                    trace("Invalid type of package sent - could not be deserialized.");

                    // Kill myself
                    fromCoordinatorChannel = null;
                    toCoordinatorChannel = null;
                    Worker.current.setSharedProperty("toWorkerChannel", null);
                    Worker.current.setSharedProperty("fromWorkerChannel", null);

                    Worker.current.terminate();
                }
            }
        }
    }
}

在原始工人中:

<?xml version="1.0" encoding="utf-8"?>
<s:WindowedApplication xmlns:fx="http://ns.adobe.com/mxml/2009" 
                       xmlns:s="library://ns.adobe.com/flex/spark" 
                       xmlns:mx="library://ns.adobe.com/flex/mx">
    <fx:Script>
        <![CDATA[
            import mx.events.FlexEvent;

            var worker:Worker;
            var to:MessageChannel;
            var from:MessageChannel;

            var graveyard:Array = new Array();


            private function removeWorkerIfFailed():void {
                if(worker && worker.state == WorkerState.TERMINATED) {
                    from.close();
                    worker = null;

                    // What the actual f***? If I allow this channel to be garbage collected, it breaks. If I prevent that, it doesn't (o.Ó)
                    graveyard.push(to);

                    to = null;
                    from = null;
                }
            }


            protected function button1_clickHandler(event:MouseEvent):void
            {
                registerClassAlias("Example", Example);

                // Create worker and channels
                worker = WorkerDomain.current.createWorker(Workers.BW);
                to = Worker.current.createMessageChannel(worker);
                from = worker.createMessageChannel(Worker.current);

                // Attach event listener to status of worker so its reference can be deleted when it fails
                worker.addEventListener(Event.WORKER_STATE,function(event:Event):void {removeWorkerIfFailed();});

                // Set shared properties so worker can access channels
                worker.setSharedProperty("toWorkerChannel", to);
                worker.setSharedProperty("fromWorkerChannel", from);                

                // Attach event listener for incoming messages 
                from.addEventListener(Event.CHANNEL_MESSAGE, function(event:Event):void { trace('incoming'); });

                // Start the worker
                worker.start();


                var example1:Example = new Example("one");
                to.send(example1);
            }
        ]]>
    </fx:Script>
    <s:Button label="Do it" click="button1_clickHandler(event)">

    </s:Button>
</s:WindowedApplication>

添加Example类

package
{
    import flash.utils.IDataInput;
    import flash.utils.IDataOutput;
    import flash.utils.IExternalizable;

    public class Example implements IExternalizable
    {
        public var name:String;
        public function Example(name:String)
        {
            this.name = name;
        }       

        public function readExternal(input:IDataInput):void
        {
            name = input.readUTF();
        }

        public function writeExternal(output:IDataOutput):void
        {
            output.writeUTF(name);
        }

    }
}

问题如下:如果我删除了removeWorkerIfFailed()中推送对数组的引用(从而阻止通道被垃圾回收)的行,则主应用程序会冻结。调试器不显示任何活动的函数调用。只要那条线存在,一切正常。

重申:我知道为了解决这个问题,我需要在后台工作程序中调用registerClassAlias(...),但我正在尝试处理这种情况,即有人抛出错误的地方后台工作者。

谢谢

0 个答案:

没有答案