Strange Flash cache behaviour and attachMovieAnywhere solution

Some days ago I’ve read about an old problem:
if I load a swf with some identifiers, I can’t “attachMovie” them anywhere, but only in the loaded movie:
[as] //If you do:
myClip.loadMovie(“libraryfile.swf”);
//then you can attach movie only in this scope: “myClip”:
myClip.attachMovie(‘clip1’, ‘foo’, myClip.getNextHighestDepth());

//this doesn’t works:
_root.attachMovie(‘clip1’, ‘foo’, _root.getNextHighestDepth());
[/as]

This can be really a problem if you decide to move some assets to external files too late in the development, probably you’ll have to rewrite substantial part of the application or it can be just impossible.

The simplest way to load an external resource and still be able to attach movies everywhere is to “Import for runtime sharing” it, but in this way you can’t control via actionscript when to load or change what file to load (for example, to change the theme).

The solution:

Since I’ve noted some strange behaviour loading files in the flash ide, I’ve opened my trusty Ethereal sniffer and I’ve found something interesting:
When flash load a clip and cache it, it will not try to reload it until the page is refreshed.
What does it mean?
[as] var mcLoader:MovieClipLoader = new MovieClipLoader();
//This send to server: GET /libraryfile.swf HTTP/1.1
mcLoader.loadClip(“libraryfile.swf”, target);

var mcLoader2:MovieClipLoader = new MovieClipLoader();
//This don’t send nothing, No bandwidth waste 🙂
mcLoader2.loadClip(“libraryfile.swf”, target2);
[/as] In the above example, after the first load, every time I’ll load “libraryfile.swf” in the movie, flash will take it from the memory and not from the server.
So I can load it everywhere I need it without using any bandwidth. In this way I can attach the loaded resources everywhere in the movie.
The next time the page is loaded, flash will ask the server for the file only the first time.

This can be a problem when we want to check if an swf was modified, in this case we have to put a ? in the filename to be sure the file will be reloaded:
[as] //This is _always_ reloaded:
clipName = “clip.swf?”+ Math.random();
[/as]

AttachMovieAnywhere:

This simple function can be useful to attach a loaded movieclip anywhere:
[as] MovieClip.prototype.attachMovieAnywhere = function(file:String, idName:String, newName:String, depth:Number, initObject:Object ) {
if(depth == undefined) depth = getNextHighestDepth();
var parent:MovieClip = this;
var container:MovieClip = this.createEmptyMovieClip(newName, depth);
var mcLoader:MovieClipLoader = new MovieClipLoader();
var listener:Object = new Object();
listener.onLoadInit = function (mc) {
mc.attachMovie(idName, newName, mc.getNextHighestDepth());
parent[newName] = parent[newName][newName];
}
mcLoader.addListener(listener);
mcLoader.loadClip(file, container);
}
[/as]

The usage is simple:
[as] var container:MovieClip = this.createEmptyMovieClip(“container”, getNextHighestDepth());
container.attachMovieAnywhere(‘foo.swf’, ‘clip’, ‘foo’);
//One frame later:
container.foo._x = 100;
[/as] The main difference from attachMovie is that the attached movieclip will not be avaible until the next frame.

Conclusions:

It is a bug? I don’t think, this isn’t much different form how a browser works: after the first occurrence of <img src="img.jpg"/>, it will not try to reload “img.jpg” if another <img src="img.jpg"/> is found.

So why I haven’t found it before? 🙂
Maybe because I have always thought that “loadClip” would have loaded file, maybe receiving a “HTTP1/1 304 Not Modified” reply, instead of silently take the cached one, who knows!

I’m sure there are plenty of experienced flash developers out there that already know this, but I’ve found many questions about this problem and I hope this can be useful to someone 🙂

 

To be sure that this stuff works I’ve made a test for it, it was useful to me to better understand how the flash cache mechanism works and to test it on many platform.
Feel free to leave a comment if something doesn’t works.
(It is sufficient to view this post to participate, the results will be stored for statistic purpose only)

10 thoughts on “Strange Flash cache behaviour and attachMovieAnywhere solution

  1. Pingback: MAB Blog » Blog Archive » AttachMovie & Loaded Clips

  2. Sarah says:

    Thank you! This post saved me a great deal of time trying to figure out how to cache massive movieclips.

    Your solution, although very simple, surprised me. I would have thought that if Flash cached files loaded by MovieClipLoader, then this code… (using the same MovieClipLoader “mcLoader” to load the same file onto the same target twice)….

    var mcLoader:MovieClipLoader = new MovieClipLoader();
    mcLoader.loadClip(“libraryfile.swf”, target);
    mcLoader.loadClip(“libraryfile.swf”, target);

    … would have worked in a similar way to the code that you provided (which uses a second MovieClipLoader “mcLoader2” and a second target “target2”)…

    var mcLoader:MovieClipLoader = new MovieClipLoader();
    mcLoader.loadClip(“libraryfile.swf”, target);
    var mcLoader2:MovieClipLoader = new MovieClipLoader();
    mcLoader2.loadClip(“libraryfile.swf”, target2);

    …but no! Using the same MovieClipLoader OR the same target on the second load clears the cache. I tested them all.

    Now that I know how this works I am very happy. Thanks again for sharing.

  3. Riccardo Bartoli says:

    Hi Madarco,
    thank you for sharing this tip. I can’t understand this:

    The main difference from attachMovie is that the attached movieclip will not be avaible until the next frame.

    With attachMovie the item it’s attached and available in the frame where the code is scoped.
    How can a movieclip be available in the next frame if it’s attached in the previous?

    Thanks a lot

  4. Madarco says:

    Hi,
    it is because attachMovieAnywhere load the movie from the net.
    The first time container.attachMovieAnywhere(‘foo.swf’, ‘clip’, ‘foo’); is executed it will load the clip from the server.
    This can take some time.
    The second time container.attachMovieAnywhere(‘foo.swf’, ‘clip’, ‘foo’); is executed it will take the file “foo.swf” from the browser cache, so the load will take the minimum amount of time: 1 frame.

  5. mite says:

    Hello,

    “Maybe because I have always thought that “loadClip” would have loaded file, maybe receiving a “HTTP1/1 304 Not Modified” reply, instead of silently take the cached one, who knows!

    Well, acually it do receives a “HTTP1/1 304 Not Modified” everytime a load call is attemp.
    flash cannot “silently take the cached one”.

    Aynway, Thanks.

  6. Madarco says:

    Are you sure?

    Sniffing the traffic (http://www.wireshark.org/) I’ve see only a request per item.

    It will try to load an url only once, then it will take the cached item at every load attempt.
    Like a browser: IE, Firefox, ecc, will load an image only the first time it occurs in a page.

    Ps: I’m referring to Flash 8, I don’t know if Flash 9 is different.

  7. mite says:

    Hi Madarco,

    Try to use Charles debugger(google it), or even apple safari debugger and you`ll see the load calls.
    I did a solution like yours some time ago to a project I was working, and it was very slow inside any browser(due the flash load a new file in every call).
    After use shared library, it speed up 200% and stop the “HTTP1/1 304 Not Modified”.
    The only shared library problem, I think, it the need to import the externals swf reference.

    I think flash 9/10 can attach others swf assets without need shared object or a solution like yours.

    Best Regards,
    Mite

  8. Madarco says:

    It may depends of the kind of headers your web server is sending.
    You should check the cache related ones.

    Btw, there is a simple test in this page, it load a movieclip from a php page that log how many request the server receive.
    If it is green, then your client is asking for the movieclip only the first time, subsequent calls doesn’t produce an http request.

    However, looking at the statistics of the test, sometimes it seems to fail, but I haven’t isolated the cause.

Comments are closed.