2009-08-15 11 views
1

J'ai essayé de créer une classe universelle de chargeur d'actifs (avec l'aide des gens de stackoverflow), qui se souvient des assets précédemment téléchargés en les stockant dans un tableau associatif.Comment étendre la classe Loader et renvoyer les actifs mis en cache dans actionscript/flex 3?

Ceci est le résultat final:

AssetLoader.as

package 
{ 
    import flash.display.Loader; 
    import flash.events.Event; 
    import flash.net.URLRequest; 
    import flash.utils.ByteArray; 

    public final class AssetLoader extends Loader 
    { 
     public static var storedAssets:Object = {}; 
     private var postUrl:String; 
     private var urlRequest:URLRequest; 
     private var cached:Boolean = false; 

     public final function AssetLoader(postUrl:String):void 
     { 
      this.postUrl = postUrl; 
      if (storedAssets[postUrl]) 
      { 
       cached = true; 
      } 
      else 
      { 
       urlRequest = new URLRequest(Settings.ASSETS_PRE_URL + postUrl); 
       contentLoaderInfo.addEventListener(Event.COMPLETE, OnAssetLoadComplete); 
      } 
     } 

     //starts loading the asset 
     public final function loadAsset():void 
     { 
      if (cached) 
      { 
       loadBytes(storedAssets[postUrl]); 
      } 
      else 
      { 
       load(urlRequest); 
      } 
     } 

     //runs when the asset download has been completed 
     private final function OnAssetLoadComplete(event:Event):void 
     { 
      storedAssets[postUrl] = contentLoaderInfo.bytes; 
     } 
    } 
} 

Settings.ASSETS_PRE_URL est égal à "http://site.com/assets/"

Maintenant, mon problème est qu'il est à l'origine du client à planter chaque fois qu'il essaie de récupérer la version des caches (la nouvelle version téléchargée fonctionne) de la classe:

var assetLdr:AssetLoader = new AssetLoader("ships/" + graphicId + ".gif"); 
assetLdr.contentLoaderInfo.addEventListener(Event.COMPLETE, onShipAssetComplete); 
assetLdr.loadAsset(); 

private function onShipAssetComplete(event:Event):void 
{ 
    var shipImage:Bitmap = Bitmap(event.target.loader.content); 
    // Do stuff with shipImage 
} 

Lorsque la version en cache est en cours de chargement, j'obtiens l'erreur suivante en néerlandais: "TypeError: Erreur # 1034: Afgedwongen typeomzetting est mislukt: kan flash.display :: MovieClip @ 5c13421 niet omzetten dans flash.display.Bitmap. à GameShip/onShipAssetComplete() "- signifie quelque chose comme" conversion de type a échoué, ne peut pas convertir flash.display :: MovieClip @ ... en flash.display.Bitmap "

Alors, je me demande, comment devrais-je étendre cette classe loader et lui faire retourner un actif en cache de la bonne manière? Est-ce que ma façon de stocker l'actif dans le tableau est peut-être invalide? ou dois-je utiliser autre chose que loadBytes dans la méthode AssetLoader?

+0

Vous avez vu SuperImage d'Eli Greenfield? Les bits de mise en cache sont vraiment sympa: http://www.quietlyscheming.com/blog/2007/01/23/some-thoughts-on-doubt-on-flex-as-the- best-option-orhow-i-fait-mon-flex-images-stop-dancing/ –

+0

Je viens de le vérifier, mais il est destiné uniquement aux images, alors que ma classe est pour tous les types d'actifs. Je sais ce qui ne va pas dans le code que j'ai posté – Tom

Répondre

3

Je ne suis pas sûr pourquoi vous insistez sur l'utilisation du contentLoaderInfo si vous encapsulez la fonctionnalité - allez de l'avant et encapsulez les données aussi.Pourquoi stocker les octets pour un objet au lieu d'une simple référence à l'objet réel?

Voici un exemple de ce que je veux dire. Jetez un oeil à un cas dégénéré ... qui est une demande qui pourrait être mis en mémoire cache mais pas parce que le laoder est dans le processus de chargement ...

package 
{ 

import flash.display.BitmapData; 
import flash.display.Sprite; 

public class TestAssetLoader extends Sprite 
{ 
    public var loader:AssetLoader; 
    public var degenerateLoader:AssetLoader; 
    public var cachedLoader:AssetLoader; 

    public function TestAssetLoader() 
    { 
     loader = new AssetLoader("picasso_blue_guitar.jpg"); 
     loader.addEventListener(AssetLoaderEvent.ASSET_LOAD_COMPLETE, handleAssetLoaded); 
     loader.loadAsset(); 

     // NOTE: you'll have to think about this case .... 
     // where an asset is in the process of loading when you get another request 
     // e.g. it isn't yet cached but is already being loaded ... 
     degenerateLoader = new AssetLoader("picasso_blue_guitar.jpg"); 
     degenerateLoader.loadAsset(); 
    } 

    private function handleAssetLoaded(event:AssetLoaderEvent):void 
    { 
     // here is your content 
     // var myImage:Bitmap = Bitmap(event.content); 

     // This is guaranteed to hit the cache 
     cachedLoader = new AssetLoader("picasso_blue_guitar.jpg"); 
     cachedLoader.loadAsset(); 
    } 
} 
} 

Le changement des actifs Loader:

package 
{ 
    import flash.display.Loader; 
    import flash.events.Event; 
    import flash.net.URLRequest; 

    public final class AssetLoader extends Loader 
    { 
     public static var ASSETS_PRE_URL:String = ""; 

     public static var storedAssets:Object = {}; 
     private var postUrl:String; 

     public final function AssetLoader(_postUrl:String):void 
     { 
       postUrl = _postUrl; 
     } 

     //starts loading the asset 
     public final function loadAsset():void 
     { 
      if(storedAssets[postUrl]) 
      { 
       trace("cached load"); 

       var resource:DisplayObject = storedAssets[postUrl]; 

       if(resource is Bitmap) 
       { 
        resource = new Bitmap(Bitmap(resource).bitmapData); 
       } 

       dispatchEvent(new AssetLoaderEvent(AssetLoaderEvent.ASSET_LOAD_COMPLETE, resource)); 
      } 
      else 
      { 
       var urlRequest:URLRequest = new URLRequest(ASSETS_PRE_URL + postUrl); 
      contentLoaderInfo.addEventListener(Event.COMPLETE, OnAssetLoadComplete); 
       load(urlRequest); 
      } 
     } 

     //runs when the asset download has been completed 
     private final function OnAssetLoadComplete(event:Event):void 
     { 
      trace("non-cached load"); 
      var loader:Loader = Loader(event.target.loader); 
      storedAssets[postUrl] = loader.content; 
      dispatchEvent(new AssetLoaderEvent(AssetLoaderEvent.ASSET_LOAD_COMPLETE, loader.content)); 
     } 
    } 
} 

et l'événement:

package 
{ 
import flash.display.DisplayObject; 
import flash.events.Event; 

public class AssetLoaderEvent extends Event 
{ 
    public static const ASSET_LOAD_COMPLETE:String = "AssetLoaderEvent_LoadComplete"; 

    public var content:DisplayObject; 

    public function AssetLoaderEvent(type:String, _content:DisplayObject, bubbles:Boolean=false, cancelable:Boolean=false) 
    { 
     content = _content; 
     super(type, bubbles, cancelable); 
    } 

    override public function clone():Event 
    { 
     return new AssetLoaderEvent(type, content, bubbles, cancelable); 
    } 

    override public function toString():String 
    { 
     return "[AssettLoaderEvent] " + type; 
    } 
} 
} 
+0

Merci beaucoup mais avez-vous essayé? Je l'ai juste implémenté dans mon code et la première image se charge bien (téléchargée), quelques secondes plus tard j'appelle la deuxième image (en cache), et ça se voit bien. Cependant, la première image disparaît soudainement lorsque la seconde image (mise en cache) est chargée. Une idée de ce qui pourrait causer cela? – Tom

+1

Yup - mon mauvais.J'ai mis à jour le code pour dupliquer la ressource Bitmap lors de l'obtention de la copie en cache. Vous ne pouvez pas ajouter le même DisplayObject à la scène avec deux parents différents. Vous pouvez à la place stocker le bitmapData dans la carte au lieu du bitmap ... c'est à vous de décider. –

+0

Merci. Donc je suppose que je dois faire le même genre de chose pour les sons, etc. – Tom

1

Vous êtes probablement au courant de cela, mais il est une bibliothèque open source pour AS3 (bulkloader) qui fait cela et bien plus encore. (Plug sans vergogne ici, depuis que je suis l'auteur.

À tout le moins, la lecture à travers le code source peut vous donner des idées sur les questions à aborder et peut-être quelques conseils de mise en œuvre.

Vive Arthur Debert

+0

Beau travail! Je ne l'ai pas utilisé parce que je pensais qu'il était destiné uniquement aux images, peut-être tort ici. Il a semblé avoir trop de fonctionnalités pour ce que je veux, ce qui conduirait à des quantités inutiles de code. – Tom

+0

Il charge n'importe quoi. C'est 16kb compilé, si c'est trop grand, couper les types de chargement dont vous n'avez pas besoin et les méthodes de commodité (getNetStream, getSound, etc), et vous devriez être bon à faire. –

Questions connexes