动态加载SWF会导致先前加载的SWF行为异常

时间:2010-03-26 19:58:07

标签: flash flex actionscript-3 dynamic-loading

我遇到了Flash和Flex的一个非常奇怪的问题。看来在某些情况下,如果在同一时间加载了另一个SWF,则无法在运行时(使用Loader)加载的SWF中的影片剪辑被实例化。以下是重现错误的程序的完整代码。它是使用mxmlc编译的,通过Ensemble Tofino

package 
{
    import flash.display.*;
    import flash.events.*;
    import flash.net.*;
    import flash.system.*;

    public class DynamicLoading extends Sprite
    {
        private var testAppDomain:ApplicationDomain;

        public function DynamicLoading()
        {
            var request:URLRequest = new URLRequest("http://localhost/content/test.swf");
            var loader:Loader = new Loader();
            loader.contentLoaderInfo.addEventListener(Event.COMPLETE, onTestLoadComplete);
            loader.load(request);
        }

        private function onTestLoadComplete(e:Event):void
        {
            var loaderInfo:LoaderInfo = LoaderInfo(e.target);
            testAppDomain = loaderInfo.applicationDomain;

            // To get the error, uncomment these lines...
            //var request:URLRequest = new URLRequest("http://localhost/content/tiny.swf");
            //var loader:Loader = new Loader();
            //loader.contentLoaderInfo.addEventListener(Event.COMPLETE, onTinyLoadComplete);
            //loader.load(request);

            // ...and comment this one:
            onTinyLoadComplete();
        }

        private function onTinyLoadComplete(e:Event = null):void
        {
            var spriteClass:Class = Class(testAppDomain.getDefinition("TopSymbol"));
            var sprite:Sprite = Sprite(new spriteClass());

            sprite.x = sprite.y = 200;

            addChild(sprite);
        }
    }
}

如上所示注释掉第二个加载操作,代码可以工作。但是,如果第二个加载操作未注释并且onLinyLoadComplete在加载第二个SWF后运行,则包含new spriteClass()的行将失败,并出现以下异常:

TypeError: Error #1034: Type Coercion failed: cannot convert flash.display::MovieClip@2dc8ba1 to SubSymbol.
    at flash.display::Sprite/constructChildren()
    at flash.display::Sprite()
    at flash.display::MovieClip()
    at TopSymbol()
    at DynamicLoading/onTinyLoadComplete()[C:\Users\...\TestFlash\DynamicLoading.as:38]

test.swf和tiny.swf是在Flash CS4中创建的。 test.swf包含两个符号,两个符号都是为ActionScript导出的,一个名为TopSymbol,另一个名为SubSymbol。 SubSymbol包含一个简单的图形(涂鸦),TopSymbol包含一个SubSymbol实例。 tiny.swf什么都没包含;它是发布一个新的空ActionScript 3项目的结果。

如果我修改test.swf以便不为ActionScript导出SubSymbol,则错误消失,但在我们的实际项目中,我们需要能够动态加载包含其他导出精灵类作为子节点的精灵类。

有关导致此问题的原因或如何解决问题的任何想法?

编辑:有几个人建议tiny.swf可以包含一个与test.swf或父类(DynamicLoading.swf)中的类同名的类。 它没有。正如我上面所说,我通过简单地发布一个全新的空Flash CS4项目来创建tiny.swf。以下是在tiny.swf上运行时swfdump -D的完整输出:

[HEADER]        File version: 10
[HEADER]        File is zlib compressed. Ratio: 41%
[HEADER]        File size: 1343
[HEADER]        Frame rate: 30.000000
[HEADER]        Frame count: 1
[HEADER]        Movie width: 550.00
[HEADER]        Movie height: 400.00
[045]         4 FILEATTRIBUTES as3 symbolclass
[04d]      1284 METADATA
[009]         3 SETBACKGROUNDCOLOR (ff/ff/ff)
[056]        11 SCENEDESCRIPTION
[001]         0 SHOWFRAME 1 (00:00:00,000)
[000]         0 END

4 个答案:

答案 0 :(得分:1)

当加载两个swfs时,我看到了时髦的行为。当两个swfs具有相同类的不同版本时,会出现问题。检查以确保TopSymbol中的SubSymbol实例与您直接加载的SubSymbol相同。

答案 1 :(得分:1)

由于有多个具有相同名称的类,这看起来似乎有问题。由于代码只要tiny.swf没有加载就可以工作,我倾向于认为这是我们的罪魁祸首。确保库确实是空的。

答案 2 :(得分:1)

根据Adobe's documentation,如果要直接访问已加载的SWF中的符号类(例如TopSymbol),则应在加载上下文中指定当前的应用程序域。所以对我来说,更大的问题是为什么第二个加载的第一个例子被注释掉了。我唯一的猜测是complete事件可能正在Loader当前应用程序域的上下文中执行。

尝试将test.swf显式加载到当前应用程序域中,如下所示:

var context:LoaderContext = new LoaderContext();
context.securityDomain = SecurityDomain.currentDomain;
context.applicationDomain = ApplicationDomain.currentDomain;

var request:URLRequest = new URLRequest("http://localhost/content/test.swf");
var loader:Loader = new Loader();
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, onTestLoadComplete);
loader.load(request, context);

修改

由于您希望确保在单独的应用程序域中加载动态加载的SWF,因此您可能希望为每次加载显式创建ApplicationDomain对象。我不知道默认情况下Loader用于其应用域的内容。尝试这样的事情:

public class DynamicLoading extends Sprite
{
    private var testAppDomain:ApplicationDomain;
    private var tinyAppDomain:ApplicationDomain;

    public function DynamicLoading()
    {
        testAppDomain = new ApplicationDomain();
        var context:LoaderContext = new LoaderContext(false, testAppDomain);
        var request:URLRequest = new URLRequest("http://localhost/content/test.swf");
        var loader:Loader = new Loader();
        loader.contentLoaderInfo.addEventListener(Event.COMPLETE, onTestLoadComplete);
        loader.load(request, context);
    }

    private function onTestLoadComplete(e:Event):void
    {
        tinyAppDomain = new ApplicationDomain();
        var context:LoaderContext = new LoaderContext(false, tinyAppDomain);
        var request:URLRequest = new URLRequest("http://localhost/content/tiny.swf");
        var loader:Loader = new Loader();
        loader.contentLoaderInfo.addEventListener(Event.COMPLETE, onTinyLoadComplete);
        loader.load(request, context);
    }

    private function onTinyLoadComplete(e:Event = null):void
    {
        var spriteClass:Class = Class(testAppDomain.getDefinition("TopSymbol"));
        var sprite:Sprite = Sprite(new spriteClass());

        sprite.x = sprite.y = 200;

        addChild(sprite);
    }
}    

答案 3 :(得分:1)

为了排除Adobe的加载类中的许多错误,我肯定会使用greensock LoaderMax库... http://www.greensock.com/loadermax/ 简单,自由+强大。