动态加载 SWF 会导致先前加载的 SWF 行为异常
我在使用 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 之后运行 onTinyLoadComplete,则包含 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
I have run into a very strange problem with Flash and Flex. It appears that under certain circumstances, movie clips from a SWF loaded at runtime (using Loader) cannot be instantiated if another SWF has been loaded in the mean time. Here is the complete code for a program that reproduces the error. It is compiled using mxmlc, via 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);
}
}
}
With the second loading operation commented out as shown above, the code works. However, if the second loading operation is uncommented and onTinyLoadComplete runs after the second SWF is loaded, the line containing new spriteClass()
fails with the following exception:
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 and tiny.swf were created in Flash CS4. test.swf contains two symbols, both exported for ActionScript, one called TopSymbol and one called SubSymbol. SubSymbol contains a simple graphic (a scribble) and TopSymbol contains a single instance of SubSymbol. tiny.swf contains nothing; it is the result of publishing a new, empty ActionScript 3 project.
If I modify test.swf so that SubSymbol is not exported for ActionScript, the error goes away, but in our real project we need the ability to dynamically load sprite classes that contain other, exported sprite classes as children.
Any ideas as to what is causing this, or how to fix it?
Edit: A couple of people have suggested that tiny.swf may contain a class with the same name as a class from test.swf or the parent (DynamicLoading.swf). It does not. As I said above, I created tiny.swf myself by simply publishing a brand-new, empty Flash CS4 project. Here is the complete output of swfdump -D
when run on 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
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
当加载两个 swf 时,我看到过奇怪的行为。当两个 swf 具有同一类的不同版本时,就会出现问题。检查以确保 TopSymbol 中的 SubSymbol 实例与直接加载的 SubSymbol 相同。
I've seen funky behavior when two swfs are loaded. The issues arises when the two swfs have different versions of the same class. Check to make sure that the SubSymbol instance within TopSymbol is the same as the the SubSymbol you're loaded directly.
由于有多个同名类,这看起来确实是个问题。由于只要没有加载tiny.swf,代码就可以工作,所以我倾向于认为这是我们的罪魁祸首。确保图书馆确实是空的。
This does seem like problem due to having more than one class with the same name. Since the code works as long as tiny.swf is not loaded, I'm incline to think that's our culprit. Make sure the library is indeed empty.
根据 Adobe的文档,如果要直接访问加载的SWF中的符号类(例如TopSymbol),则应该在加载上下文中指定当前应用程序域。所以对我来说,更大的问题是为什么你的第一个例子第二次加载被注释掉了。我唯一的猜测是,
complete
事件可能在Loader
当前应用程序域的上下文中执行。尝试将 test.swf 显式加载到当前应用程序域中,如下所示:
编辑:
由于您希望确保动态加载的 SWF 加载到单独的应用程序域中,因此您可能需要显式创建自己的每次加载的
ApplicationDomain
对象。我不知道Loader
默认情况下使用什么作为其应用程序域。尝试这样的事情:According to Adobe's documentation, if you want to directly access symbol classes in a loaded SWF (such as TopSymbol), you should specify the current application domain in the loading context. So for me, the bigger question is why your first example with the second loading commented out works. My only guess is that the
complete
event may be executing in the context of theLoader
's current application domain.Try explicitly loading test.swf into the current application domain, like this:
Edit:
Since you're wanting to make sure dynamically loaded SWFs are loaded in a separate application domain, you may want to explicitly create your
ApplicationDomain
object for each loading. I have no idea whatLoader
uses for its app domain by default. Try something like this:为了排除 Adobe 加载类中的许多错误,我肯定会使用 greensock LoaderMax 库......
http://www.greensock.com/loadermax/
简单、免费+强大。
To rule out the many bugs in Adobe's loading classes, i'd definitely use the greensock LoaderMax library...
http://www.greensock.com/loadermax/
Simple, free + powerful.