Динамическая загрузка SWF приводит к неправильной работе ранее загруженных SWF - PullRequest
4 голосов
/ 26 марта 2010

У меня возникла очень странная проблема с 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);
        }
    }
}

После второй операции загрузки, закомментированной, как показано выше, код работает. Однако, если вторая операция загрузки не закомментирована и onTinyLoadComplete запускается после загрузки второго 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, чтобы SubSymbol не экспортировался для ActionScript, ошибка исчезнет, ​​но в нашем реальном проекте нам понадобится возможность динамически загружать классы спрайтов, которые содержат другие экспортируемые классы спрайтов, как дочерние.

Есть какие-нибудь идеи относительно того, что вызывает это, или как это исправить?

Редактировать: Несколько человек предположили, что tiny.swf может содержать класс с тем же именем, что и класс из test.swf или родительский (DynamicLoading.swf). Это не так. Как я уже говорил выше, я сам создал tiny.swf, просто опубликовав новый пустой проект Flash CS4. Вот полный вывод swfdump -D при запуске на tiny.swf:

[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 ]

1 голос
/ 04 февраля 2011

Чтобы исключить множество ошибок в классах загрузки Adobe, я бы определенно использовал библиотеку greensock LoaderMax ... http://www.greensock.com/loadermax/ Простой, бесплатный + мощный.

1 голос
/ 01 апреля 2010

Это похоже на проблему из-за наличия более одного класса с одним именем. Поскольку код работает до тех пор, пока tiny.swf не загружен, я склонен думать, что это наш виновник. Убедитесь, что библиотека действительно пуста.

1 голос
/ 03 апреля 2010

Согласно документации Adobe , если вы хотите получить прямой доступ к классам символов в загруженном 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);

Edit:

Поскольку вы хотите убедиться, что динамически загруженные 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);
    }
}    
1 голос
/ 26 марта 2010

Я видел странное поведение при загрузке двух SWF-файлов. Проблемы возникают, когда два swfs имеют разные версии одного и того же класса. Убедитесь, что экземпляр SubSymbol в TopSymbol совпадает с экземпляром SubSymbol, который вы загружаете напрямую.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...