2009-12-12 8 views
4

J'essaie de faire quelque chose d'extrêmement simple: écrire une fonction qui lit le texte d'un fichier texte et renvoie le texte dans une chaîne en utilisant AS3.Chargement et retour de données texte avec ActionScript 3 (URLLoader)

La fonction

public function readData(path:String):String 
    { 
     var dataSet:String; 

     var urlRequest:URLRequest = new URLRequest(path); 
     var urlLoader:URLLoader = new URLLoader(); 
     urlLoader.dataFormat = URLLoaderDataFormat.TEXT; 
     urlLoader.addEventListener(Event.COMPLETE, urlLoader_complete); 
     urlLoader.load(urlRequest); 

     function urlLoader_complete(evt:Event):void { 
      dataSet = urlLoader.data; 
      trace(dataSet) 
     } 
     trace(dataSet); 
     return dataSet; 
    } 

Appel de la fonction

var dataString:String = aq.readData("http://example.com/data.txt"); 
    trace(dataString); 

Ce code renvoie une chaîne vide quand je le lance. Pourquoi?

EDIT: Ok, je vois maintenant que cela ne fonctionne pas car urlLoader agit de manière asynchrone. J'écris un programme qui lit dans un fichier de données et agit dessus. Cela signifie-t-il que je dois écrire le reste de mon programme à l'intérieur de function urlLoader_complete? Ou devrais-je mettre le programme en pause jusqu'à ce que urlLoader soit terminé?

+0

promouvoir 'urlLoader_complete()' être une fonction de classe au lieu d'une fonction locale, puis Utilisez-le pour continuer votre programme. Vous pouvez utiliser des rappels, des événements, ou 'Signals' (https://github.com/robertpenner/as3-signals) pour notifier votre autre code que le chargement a terminé – divillysausages

Répondre

3

Dans Flash et Flex, toutes les E/S réseau sont asynchrones. Cela doit être fait de cette façon afin d'éviter de bloquer votre navigateur. En conséquence, il n'est pas possible d'écrire une fonction readData() qui renvoie directement le résultat d'une opération de lecture réseau. Vous devrez passer une fonction de rappel à la fonction readData(). Lorsque readData() a fini de lire les données, il peut appeler la fonction de rappel.

Par exemple:

/** 
* Asynchronous function to read data as a string. When the data has been read, 
* the callback function is called with the result. 
* 
* @param path  the URL to read 
* @param callback the function that is called with the result; should take 
*     one string argument. 
*/ 
public function readData(path:String, callback:Function):void 
{ 
    var dataSet:String; 

    var urlRequest:URLRequest = new URLRequest(path); 
    var urlLoader:URLLoader = new URLLoader(); 
    urlLoader.dataFormat = URLLoaderDataFormat.TEXT; 
    urlLoader.addEventListener(Event.COMPLETE, urlLoader_complete); 
    urlLoader.load(urlRequest); 

    function urlLoader_complete(evt:Event):void { 
     dataSet = urlLoader.data; 
     trace(dataSet); 
     callback(dataSet); 
    } 
} 

Voici comment vous pouvez appeler cette fonction de Flex:

<mx:Label id="mylabel" /> 
<mx:Button click="readData('http://www.google.com/', 
    function(s:String):void {mylabel.text = s})" /> 
+0

Hey Mike, s'avère que votre suggestion ne m'a pas donné quoi J'avais besoin parce que je cherche à créer une séquence d'actions. Jetez un oeil à mes modifications ci-dessus. – terrace

+2

C'est l'une des choses les plus délicates à propos de la programmation ActionScript (et de la programmation JavaScript, qui a le même problème): Certaines choses sont asynchrones, et il n'y a vraiment rien que vous puissiez faire pour empêcher cela. La seule chose que vous pouvez faire est de s'adapter à ce modèle asynchrone. Dans mon exemple, vous écrivez l'étape suivante de votre programme dans la fonction callback(). Si vous voulez indiquer à l'utilisateur qu'il devrait attendre, vous pouvez changer le curseur (google "flex wait cursor") ou dessiner un fileur ou afficher le mot "Loading ..." ou quelque chose. –

+0

Je suppose que je pourrais faire un: while (dataSet == null) {if (ensemble de données! = Null) {break; } else {trace ("charger des données")}}? – terrace

1

Son été il y a 3 ans que cette question a été soulevée avec vous, mais depuis que je suis tombé sur ce problème il y a quelques heures, et a réussi à le faire fonctionner et pensé pourquoi ne pas le partager. Il pourrait y avoir de meilleures alternatives déjà, mais bon je viens de commencer à coder Actionscript donc pas de reproches :)

D'abord construire une classe Preloader avec un classeur. Il y aura un paramètre numFiles dans le constructeur qui contient le nombre total de fichiers à charger. Chaque fois que la méthode complète est appelée, 1 au filtre de nom de fichier sera ajouté et une instruction vérifiera si tous les fichiers sont chargés. lorsque numFiles est égal au compteur, appelez la méthode start() de la classe appelante.

* Preloader.as *

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

    public class Preloader 
    { 
     public var urlLoader:URLLoader; 
     public var response:Array = new Array(); 
     public var callingClass:Object; 
     public var numFiles:uint; 
     private var counter:uint; 

     public function Preloader(callingClass:Object, numfiles:uint) 
     { 
      this.callingClass = callingClass; 
      this.numFiles = numFiles; 
     } 

     public function load(name:String):void 
     { 
      var request:URLRequest = new URLRequest(name); 
      urlLoader = new URLLoader(); 
      urlLoader.addEventListener(Event.COMPLETE, onLoad); 
      urlLoader.load(request); 
     } 

     public function onLoad(event:Event):void 
     { 
      response[counter] = event.currentTarget.data; 
      if(numFiles == counter) { 
       callingClass.start(); 
      } else { 
       counter++; 
      } 
     } 
    } 
} 

La méthode constructeur dans la classe d'appel devra appeler tous les fichiers de pré-charge et la méthode de démarrage sera le remplacement de votre truc constructeur. noter que lorsque les charges de préchargement, il faut la référence à sa classe d'appel et le nombre total de « à charger » fichiers:

package 
{ 
    import flash.display.MovieClip; 
    import misc.Preloader; 

    public class Path extends MovieClip 
    { 
     public var preloader:Preloader = new Preloader(this, 3); //pass this class and the total number of files 

     public function Controller() 
     {  
      preloader.loadJSON('file1.js'); 
      preloader.loadJSON('file2.js'); 
      preloader.loadJSON('file3.js'); 
     } 

     public function start():void 
     { 
      trace(preloader.response[0]); //Get first file contents 
     } 

    } 
} 
+0

Hah! Merci de répondre. Trois ans plus tard, j'apprends juste node.js et j'ai rencontré exactement le même problème. Cette fois-ci, c'est différent, car il y a une mine d'informations en ligne sur la programmation asynchrone et la synchronisation et sur la façon d'éviter la redoutable «pyramide des rappels», sans parler des tonnes de bibliothèques pour gérer le problème. – terrace

Questions connexes