Gegevens laden met opdrachten

Het is heel gebruikelijk om externe gegevens (zoals SWF-bestanden) te laden tijdens runtime, maar alleen wanneer de gegevens volledig zijn geladen, kunnen we de inhoud ervan lezen of manipuleren. Meestal moeten we luisteren naar de complete gebeurtenis verzonden door een lader of URLLoader object dat de gegevens laadt voor afhandeling van afhandeling. Vaak schrijven we code die de gegevens in één functie laadt en code schrijven die de voltooiing van het laden in een andere functie afhandelt, maar dit kan worden verbeterd door het hele laadproces samen te groeperen ...

Deze zelfstudie laat zien hoe je een laadextensie maakt in het opdrachtraamwerk in mijn vorige zelfstudie, Thinking in Commands deel 1 van 2, om het laden van de voltooiingsafhandeling in één plaats in te pakken. Deze laadextensie kan ook worden gecombineerd met het scènemanagementraamwerk dat wordt behandeld in Thinking in Commands deel 2 van 2. Veel lessen die in deze zelfstudie worden gebruikt, worden behandeld in de vorige zelfstudie, dus ik raad u ten zeerste aan de vorige zelfstudies te lezen voordat u verder gaat.

Bovendien introduceert deze zelfstudie het concept van gegevensmanager, een centrale "bank" die verwijzingen naar gegevensobjecten opslaat. U kunt gegevens bij de gegevensmanager registreren met een unieke sleutelreeks en later toegang krijgen tot de gegevens door de bijbehorende sleutelreeks op te geven. Dit spaart u de moeite om verwijzingen van gegevensobjecten en sommige problemen met variabele reikwijdte te behouden.

Overigens heeft u het GreenSock Tweening Platform nodig om deze voorbeelden te voltooien.


Waarom gegevens laden met opdrachten?

Normaal gesproken verwerken we de geladen gegevens binnen de volledige gebeurtenislistenerfunctie. Hierdoor worden twee stukjes code verbroken die logisch verbonden zijn. En door naar de code te kijken, kan uw gedachtestroom worden onderbroken als uw zicht van de laadfunctie naar de luisteraar van het volledige evenement springt.

Laten we eens kijken naar de logische stroom van een naïeve SWF-laadbenadering.

De lader laadt een SWF van een URL en de onComplete () functie wordt aangeroepen door de dispatchEvent () methode die een volledige gebeurtenis verzendt, waarbij de dispatchEvent () methode wordt intern aangeroepen door de loader. Nou, eigenlijk wordt het aangeroepen door de LoaderInfo object dat bij de. behoort lader object, maar voor de eenvoud, laten we het gewoon zeggen dispatchEvent () methode wordt aangeroepen door de lader.

Vervolgens, binnen de onComplete () functie, de doMoreStuff () functie wordt aangeroepen nadat de laadvoltooiingshandeling is voltooid en, zoals de naam van de functie doet vermoeden, meer dingen doet.

De logische stroom op hoog niveau is erg lineair: roep de Loader.load () methode eerst, onComplete () ten tweede, en doMoreStuff () derde. Zoals u echter uit het diagram zult opmerken, is de aanroeping van elke functie ingebed in de hoofdtekst van de vorige, wat resulteert in een "geneste" code. Naar mijn mening, als de logische stroom van een bepaalde functionaliteit lineair is, moet de bijbehorende code lineair worden geschreven, niet genest. Anders kan de code soms verwarrend zijn als het niveau van de aanroepingsnest te hoog is.

Dit is wanneer de Command-aanpak in het spel komt. Uit het onderstaande diagram kunnen we zien dat de code behoorlijk lineair is met behulp van commando's, in die zin dat alle commando's lineair aan elkaar worden gekoppeld door een serieel commando. Hoewel het programma "omgeleid" naar de setProperties (), addChildLoader (), en doMoreStuff () functies; hun aanroeping is lineair.


Gegevens manager

Goed, voordat we verder gaan met laden, laten we eerst eens kijken naar de Gegevens manager klasse. Met een gegevensbeheer kunt u een sleutelreeks koppelen aan een gegevensobject en kunt u overal in uw code een verwijzing naar dit gegevensobject aanvragen. Met de gegevensmanager hoeft u zich geen zorgen te maken over het bijhouden van gegevensverwijzingen en variabele scopes. Het enige wat u hoeft te doen, is een stuk gegevens registreren bij de manager met een sleutelstring.

De codering is vrij eenvoudig, zoals hieronder getoond:

 pakketgegevens import flash.utils.Dictionary; public class DataManager // een woordenboek dat de string-gegevensrelaties onderhoudt private static var _data: Dictionary = new Dictionary (); // retourneert het gegevensobject dat is gekoppeld aan een sleutelstring openbare statische functie getData (key: String): * return _data [key];  // registreert een data-object met een sleutelstring public static function registerData (key: String, data: *): void _data [key] = data;  / / registreert een sleutel string openbare statische functie unregisterData (key: String): void delete _data [key];  / / registreert alle sleutellijnen ongedaan openbare statische functie clearData (): void for (var key: String in _data) delete _data [key]; 

Dus als we een key string "myData" willen registreren met een data-object - zeg, een sprite - zouden we de code als volgt kunnen schrijven:

 var sprite: Sprite = nieuwe Sprite (); DataManager.registerData ("myData", sprite);

Later, ergens in de code, kunnen we de volgende code schrijven om een ​​verwijzing naar de sprite te verkrijgen en deze aan een weergavelijst toe te voegen. Het is zo simpel, geen problemen meer met het onderhouden van objectreferenties en variabele scopes.

 var sprite: Sprite = DataManager. getData ("myData") als Sprite; container.addChild (sprite);

Naïeve laadaanpak

Laten we nu eens kijken hoe de naïeve laadbenadering een extern beeld laadt. De laadcode ligt in één functie en de code voor de afhandelingshandeling ligt in een andere. We gaan drie afbeeldingen laden en toevoegen aan het podium wanneer het laden is voltooid. We houden ook de voortgang van het laden in de gaten door naar de voortgangsevents te luisteren.


Stap 1: Maak een Flash-document

Open Flash en maak een nieuw Flash-document.

Stap 2: Maak een voortgangsbalk

Teken een voortgangsbalk op het podium; dit is om de voortgang van het laden aan te geven. Converteer de volledige voortgangsbalk naar een symbool en geef het een instantienaam van "progressBar_mc". Verwerk, binnen het voortgangsbalk symbool, de innerlijke voortgangsbalk naar een ander symbool en geef het een instantienaam van "innerBar_mc".


Stap 3: bereid de afbeeldingen voor

Plaats drie afbeeldingen in dezelfde map als het FLA-bestand met de naam "image1.jpg", "image2.jpg" en "image3.jpg". Dit is hoe de drie afbeeldingen eruit zien.


Stap 4: Maak de documentklasse

Maak een nieuw AS-bestand voor de documentklasse voor het FLA-bestand. De code is vrij eenvoudig en alle details worden uitgelegd in de opmerkingen. Eerst worden drie laders gemaakt en begint het laden. Bij elke voortgangsgebeurtenis wordt de voortgangsbalk bijgewerkt. Wanneer het laden is voltooid, vervaagt de voortgangsbalk en vervagen de drie afbeeldingen één voor één.

 pakket import com.greensock.TweenMax; import flash.display.DisplayObject; import flash.display.Loader; import flash.display.MovieClip; import flash.events.Event; import flash.events.ProgressEvent; import flash.net.URLRequest; public class NaiveLoading breidt MovieClip uit private var loader1: Loader; private var loader2: Loader; private var loader3: Loader; openbare functie NaiveLoading () // voortgangsbalk verkleinen naar voortgang nulschaalBar_mc.innerBar_mc.scaleX = 0; // create laders loader1 = new Loader (); loader2 = new Loader (); loader3 = nieuwe Loader (); // voeg progress listeners toe loader1.contentLoaderInfo.addEventListener (ProgressEvent.PROGRESS, onProgress); loader2.contentLoaderInfo.addEventListener (ProgressEvent.PROGRESS, onProgress); loader3.contentLoaderInfo.addEventListener (ProgressEvent.PROGRESS, onProgress); // voeg completeringsluisteraars toe loader1.contentLoaderInfo.addEventListener (Event.COMPLETE, onComplete); loader2.contentLoaderInfo.addEventListener (Event.COMPLETE, onComplete); loader3.contentLoaderInfo.addEventListener (Event.COMPLETE, onComplete); // begin loader1.load te laden (nieuwe URLRequest ("image1.jpg")); loader2.load (nieuwe URLRequest ("image2.jpg")); loader3.load (nieuwe URLRequest ("image3.jpg"));  private function onProgress (e: ProgressEvent): void // totale bits berekenen om te laden var bytesTotal: uint = 0; bytesTotal + = loader1.contentLoaderInfo.bytesTotal; bytesTotal + = loader2.contentLoaderInfo.bytesTotal; bytesTotal + = loader3.contentLoaderInfo.bytesTotal; // bereken totale bits geladen var bytesLoaded: uint = 0; bytesLoaded + = loader1.contentLoaderInfo.bytesLoaded; bytesLoaded + = loader2.contentLoaderInfo.bytesLoaded; bytesLoaded + = loader3.contentLoaderInfo.bytesLoaded; // update progress bar scale progressBar_mc.innerBar_mc.scaleX = bytesLoaded / bytesTotal;  private var _completeCount: int = 0; private function onComplete (e: Event): void _completeCount ++; if (_completeCount < 3) return; //remove progress listeners loader1.contentLoaderInfo.removeEventListener(ProgressEvent.PROGRESS, onProgress); loader2.contentLoaderInfo.removeEventListener(ProgressEvent.PROGRESS, onProgress); loader3.contentLoaderInfo.removeEventListener(ProgressEvent.PROGRESS, onProgress); //remove completion listeners loader1.contentLoaderInfo.removeEventListener(Event.COMPLETE, onComplete); loader2.contentLoaderInfo.removeEventListener(Event.COMPLETE, onComplete); loader3.contentLoaderInfo.removeEventListener(Event.COMPLETE, onComplete); var image1:DisplayObject = loader1.content; var image2:DisplayObject = loader2.content; var image3:DisplayObject = loader3.content; //adjust loaded image positions image1.x = 30, image1.y = 30; image2.x = 230, image2.y = 30; image3.x = 430, image3.y = 30; //add loaded images to display list addChild(image1); addChild(image2); addChild(image3); //fade out progress bar TweenMax.to(progressBar_mc, 0.5, autoAlpha:0, blurFilter:blurX:20, blurY:20); //fade in loaded images TweenMax.from(image1, 0.5, delay:0.5, alpha:0, blurFilter:blurX:20, blurY:20); TweenMax.from(image2, 0.5, delay:0.7, alpha:0, blurFilter:blurX:20, blurY:20); TweenMax.from(image3, 0.5, delay:0.9, alpha:0, blurFilter:blurX:20, blurY:20);   

Stap 5: Test de film

Druk op CTRL + ENTER om de film te testen. Je zult zien dat de voortgangsbalk onmiddellijk vervaagt en de drie afbeeldingen vervagen. Dat komt omdat de afbeeldingen lokale bestanden zijn, wat betekent dat ze bijna onmiddellijk kunnen worden geladen. Om de online downloadsnelheid te simuleren, selecteert u eerst de Weergave> Downloadinstellingen> DSL als de gesimuleerde downloadsnelheid en druk vervolgens nogmaals op CTRL + ENTER zonder het testvenster te sluiten om het online downloaden te simuleren. Deze keer zul je zien dat de voortgang steeds groter wordt voordat het vervaagt.

Oké, het is tijd om de afbeeldingen te laden met het opdrachtraamwerk.


Utility-opdrachten

Voordat we verder gaan, laten we een aantal hulpprogrammaopdrachten maken die later in het voorbeeld worden gebruikt. Nogmaals, deze opdrachtklassen zijn gebaseerd op het opdrachtraamwerk dat in mijn vorige zelfstudie (deel 1) werd gepresenteerd, en ik beveel ten zeerste aan dat je ze doorneemt voordat je verdergaat. Als u de zelfstudie eerder hebt gelezen, kunt u altijd teruggaan als u uw geheugen moet vernieuwen.

Data Managers-opdrachten

Hier gaan we twee opdrachten maken voor het registreren en afmelden van gegevens voor de gegevensmanagerklasse. De RegisterData commando registreert gegevens naar de manager, terwijl de UnregisterData commando unregisters data.

 pakket commands.data import commands.Command; import data.DataManager; // dit commando registreert data naar de datamodel public class RegisterData extends Command public var key: String; openbare var-gegevens: *; public function RegisterData (key: String, data: *) this.key = key; this.data = data;  override protected function execute (): void DataManager.registerData (key, data); compleet(); 
 pakket commands.data import commands.Command; import data.DataManager; // deze opdracht maakt het afmelden van data uit de datamanager public class UnregisterData breidt Command uit public var key: String; openbare functie UnregisterData (key: String) this.key = key;  override protected function execute (): void DataManager.unregisterData (key); compleet(); 

Het LoaderLoad-commando

Deze opdracht bevat een a lader -instantie laden() methode. U kunt een onProgress commando dat wordt uitgevoerd bij elke voortgangsgebeurtenis en een onComplete uitgevoerd wanneer het laden voltooid is. Merk op dat de compleet() methode wordt aangeroepen wanneer het laden voltooid is. Deze coderegel is uiterst cruciaal. Als u de methode niet aanroept, wordt de opdracht nooit als voltooid beschouwd, waardoor uw hele applicatie in het ergste geval vastloopt.

 pakket commands.loading import commands.Command; import flash.display.Loader; import flash.events.Event; import flash.events.ProgressEvent; import flash.net.URLRequest; import flash.system.LoaderContext; public class LoaderLoad breidt Command uit public var loader: Loader; public var url: URLRequest; public var context: LoaderContext; public var onProgress: Command; public var onComplete: Command; openbare functie LoaderLoad (loader: Loader, url: URLRequest, context: LoaderContext = null, onProgress: Command = null, onComplete: Command = null) this.loader = loader; this.url = url; this.context = context; this.onProgress = onProgress; this.onComplete = onComplete;  override protected function execute (): void // add listeners loader.contentLoaderInfo.addEventListener (ProgressEvent.PROGRESS, progressListener); loader.contentLoaderInfo.addEventListener (Event.COMPLETE, completeListener); loader.contentLoaderInfo.addEventListener (Event.COMPLETE, loadingComplete); // begin met laden loader.load (url, context);  private function loadingComplete (e: Event): void // listeners verwijderen loader.contentLoaderInfo.removeEventListener (ProgressEvent.PROGRESS, progressListener); loader.contentLoaderInfo.removeEventListener (Event.COMPLETE, completeListener); loader.contentLoaderInfo.removeEventListener (Event.COMPLETE, loadingComplete); compleet();  private function progressListener (e: ProgressEvent): void // voer het onProgress-commando uit als (onProgress) onProgress.start ();  private function completeListener (e: Event): void // voer de opdracht onComplete uit als (onAanvullen) onComplete.start (); 

Het commando InvokeFunction

Deze opdracht bevat de aanroep van een andere functie. Het is ontworpen om u een extra parameterarray te bieden voor de functie die moet worden opgeroepen.

 pakket commands.utils import commands.Command; // deze opdracht roept een functie aan openbare klasse InvokeFunction breidt Command uit public var func: Function; public var args: Array; openbare functie InvokeFunction (func: Function, args: Array = null) this.func = func; this.args = args;  override protected function execute (): void func.apply (null, args); compleet(); 

Dat is het. Tijd voor het voorbeeld.


Stap 1: kopieer het Flash-documentbestand

Kopieer het FLA-bestand van het vorige voorbeeld naar een nieuwe map en kopieer de beeldbestanden erbij.


Stap 2: Maak de documentklasse

Maak een nieuw AS-bestand voor de documentklasse van het gekopieerde FLA-bestand, genaamd "LoadingDataWithCommands". Vergeet niet de naam van de documentklasse in het FLA-bestand naar deze nieuwe te wijzigen.

De code voor de documentklasse is redelijk schoon. Het stelt eenvoudig de huidige scène in op a LoadingScene met een scènemanager. We gebruiken het scènekader dat in mijn vorige zelfstudie werd gepresenteerd (deel 2). U kunt het bekijken als u bent vergeten hoe u het moet gebruiken.

 pakket import flash.display.MovieClip; import scenes.SceneManager; public class LoadingDataWithCommands breidt MovieClip uit public function LoadingDataWithCommands () var sceneManager: SceneManager = new SceneManager (); sceneManager.setScene (nieuw LoadingScene (this)); 

Er zijn in totaal twee scènes. De LoadingScene laadt de afbeeldingen en werkt de voortgangsbalk bij. Nadat het laden is voltooid, gaat de scène over naar de MainScene, welke verdwijnt in de geladen afbeeldingen.


Stap 3: De laadscène

Verleng de Tafereel klasse om een ​​nieuwe klasse met de naam te maken LoadingScene. De houder eigenschap bevat een verwijzing naar de hoofdsprite. Hierdoor hebben we later toegang tot de voortgangsbalk.

 pakket import scenes.Scene; openbare klasse LoadingScene breidt Scene uit private var container: LoadingDataWithCommands; openbare functie LoadingScene (container: LoadingDataWithCommands) this.container = container; 

Maak nu de intro-opdracht voor de laadscene. De intro maakt drie laders en begint het laadproces. Dit wordt gedaan door het overschrijven van de createIntroCommand () methode. De volgende code gaat in de klasse body, hetzelfde als de constructor.

 // de intro-opdracht begint met het laden van de drie afbeeldingen die de openbare functie overschrijven createIntroCommand (): Command var loader1: Loader = new Loader (); var loader2: Loader = new Loader (); var loader3: Loader = new Loader (); var command: Command = new ParallelCommand (0, // verkleinen van de voortgangsbalk naar nul schaal nieuwe SetProperties (container.progressBar_mc.innerBar_mc, scaleX: 0), // laden-gerelateerde commando's uitgevoerd in serie nieuwe SerialCommand (0, / / registreert de drie laders voor de gegevensmanager nieuwe ParallelCommand (0, nieuwe RegisterData ("loader1", loader1), nieuwe RegisterData ("loader2", loader2), nieuwe RegisterData ("loader3", loader3)), // start drie keer laden opdrachten in parallelle nieuwe ParallelCommand (0, nieuwe LoaderLoad (loader1, nieuwe URLRequest ("image1.jpg"), null, nieuwe InvokeFunction (onProgress) // onProgress-opdracht), nieuwe LoaderLoad (loader2, nieuwe URLRequest ("image2.jpg") , null, nieuwe InvokeFunction (onProgress) // onProgress-opdracht), nieuwe LoaderLoad (loader3, nieuwe URLRequest ("image3.jpg"), null, nieuwe InvokeFunction (onProgress) // onProgress-opdracht)))); terugkeer commando; 

Behandel vervolgens de onSceneSet () methode. Deze methode wordt aangeroepen wanneer de intro-opdracht is voltooid, om aan te geven dat het laden is voltooid. Binnen deze methode vertellen we de scènemanager om door te gaan naar de hoofdscène. Vóór de overgang van de scène wordt eerst het outro-commando uitgevoerd.

 override public function onSceneSet (): void sceneManager.setScene (new MainScene (container)); 

En dan overschrijven de createOutroCommand. Dit commando zal de voortgangsbalk doen vervagen.

 // het outro-commando vervaagt de voortgangsbalk override public function createOutroCommand (): Command var command: Command = new SerialCommand (0, // fade out progress bar new TweenMaxTo (container.progressBar_mc, 0.5, autoAlpha: 0, blurFilter : blurX: 20, blurY: 20), // verwijder de voortgangsbalk uit de weergavelijst new RemoveChild (container, container.progressBar_mc)); terugkeer commando; 

Maak ten slotte de onProgress methode aangeroepen door de InvokeFunction commando's.

 private function onProgress (): void // laad loader-referenties op van de datamanager var loader1: Loader = DataManager.getData ("loader1") als Loader; var loader2: Loader = DataManager.getData ("loader2") als Loader; var loader3: Loader = DataManager.getData ("loader3") als Loader; // bereken totale bits om te laden var bytesTotal: uint = 0; bytesTotal + = loader1.contentLoaderInfo.bytesTotal; bytesTotal + = loader2.contentLoaderInfo.bytesTotal; bytesTotal + = loader3.contentLoaderInfo.bytesTotal; // bereken totale bits geladen var bytesLoaded: uint = 0; bytesLoaded + = loader1.contentLoaderInfo.bytesLoaded; bytesLoaded + = loader2.contentLoaderInfo.bytesLoaded; bytesLoaded + = loader3.contentLoaderInfo.bytesLoaded; // update voortgangsschaal container.progressBar_mc.innerBar_mc.scaleX = bytesLoaded / bytesTotal; 

Stap 4: De hoofdscène

Creëer nu een nieuwe klasse voor de hoofdscène, breid de uit Tafereel klasse.

 pakket import scenes.Scene; public class MainScene breidt Scene uit private var container: LoadingDataWithCommands; openbare functie MainScene (container: LoadingDataWithCommands) this.container = container; 

Overschrijf de createIntroCommand () methode. Deze methode voegt de loaders toe aan de displaylijst en vervaagt ze één voor één. Bovendien worden de snaren voor de gegevenssleutel niet geregistreerd vanuit de gegevensbeheerder.

 override public function createIntroCommand (): Command // laad loader-referenties op uit de datamanager var loader1: Loader = DataManager.getData ("loader1") als Loader; var loader2: Loader = DataManager.getData ("loader2") als Loader; var loader3: Loader = DataManager.getData ("loader3") als Loader; var-opdracht: Command = new ParallelCommand (0, // loaded-image-handling-opdrachten nieuwe SerialCommand (0, // aanpassen geladen afbeeldingposities nieuwe ParallelCommand (0, nieuwe SetProperties (loader1, x: 30, y: 30), nieuwe SetProperties (loader2, x: 230, y: 30), nieuwe SetProperties (loader3, x: 430, y: 30)), // voeg geladen afbeeldingen toe om lijst weer te geven nieuwe ParallelCommand (0, nieuwe AddChild (container , loader1), nieuwe AddChild (container, loader2), nieuwe AddChild (container, loader3)), // vervagen in geladen afbeeldingen nieuw ParallelCommand (0, nieuwe TweenMaxFrom (loader1, 0.5, blurFilter: blurX: 20, blurY: 20 ), nieuwe TweenMaxTo (loader1, 0.5, autoAlpha: 1), nieuwe TweenMaxFrom (loader2, 0.5, delay: 0.2, alpha: 0, blurFilter: blurX: 20, blurY: 20), nieuwe TweenMaxTo (loader2, 0.5, delay: 0.2, autoAlpha: 1), nieuwe TweenMaxFrom (loader3, 0.5, delay: 0.4, alpha: 0, blurFilter: blurX: 20, blurY: 20), nieuwe TweenMaxTo (loader3 , 0,5, delay: 0.4, autoAlpha: 1))), // unregsiter-gegevens van de gegevensmanager nieuwe ParallelCommand (0, nieuwe UnregisterData ("loader1"), nieuwe Unregi sterData ("loader2"), nieuwe UnregisterData ("loader3"))); terugkeer commando; 

Stap 5: Test de film

Alright. Werden gedaan! Test de film en simuleer online downloaden. U zult exact hetzelfde resultaat zien als in het vorige voorbeeld, maar deze keer is alles gedaan met het opdrachtraamwerk en het scènekader.


Samenvatting

In deze zelfstudie heb ik je laten zien hoe je externe afbeeldingen kunt laden met het opdrachtraamwerk. De LoaderLoad commando kan ook worden gebruikt om externe SWF-bestanden te laden. Bovendien kunt u uw eigen opdrachten maken om externe gegevens, behalve afbeeldingen en SWF-bestanden, te laden door de URLLoader klasse in je commando's.

We hebben meer code geschreven in het tweede voorbeeld dan de eerste. Onthoud dat het doel van het gebruik van het opdrachtraamwerk en het scènekader niet hetzelfde resultaat met minder code is, maar de code systematisch en modulair benadert, waardoor uw leven eenvoudiger wordt als het gaat om toekomstig onderhoud en modificatie.

In het eerste voorbeeld wordt alle code samengevoegd tot één enkele klasse, waardoor het voor toekomstig onderhoud moeilijk wordt als de codehoeveelheid extreem groot wordt. Het tweede voorbeeld daarentegen scheidt logisch onafhankelijke code in verschillende scènes, waardoor toekomstige wijzigingen gemakkelijker worden. Ook hebben we door integratie met het opdrachtraamwerk en het scènekader plaats gemaakt voor toekomstige uitbreiding, waar we meer scènes en intro / outro-opdrachten kunnen toevoegen zonder de irrelevante code te verstoren..

!