PictureSender = URLLoader med upload progress

Kategori: Tips og tricks | Kommentarer (2)
Gemt: 2009-02-11 14:50


I den Facebook applikation som vi er igang med i øjeblikket kan brugerne manipulere et billede, som vi tager et “screenshot” af og encoder med den glimrende PNGEncoder fra as3corelib - så langt, så godt.

Men, når det herefter skal sendes til serveren med URLLoader, så er det knapt så godt.

For det første, så har URLLoader ganske vidst en Event.PROGRESS som man kan lytte på, men den har kun med download af data af gøre og ikke upload, som det principielt er når vi sender billedet til serveren.
Det betyder så, at vi ikke har mulighed for at give nyttig feedback til brugeren i form af “10% uploaded”, og når der er tale om filer af en hvis størrelse, så kan der dermed sagtens gå både 5, 10 og 15 sekunder uden ordentligt feedback.

For det andet, så har der været et mærkeligt problem på brugere som har brugt en kombination af Mac+Safari, hvor der ganske enkelt engang imellem aldrig er kommet noget svar tilbage fra serveren, og det på trods af at jeg lytter på alle potentielle events, både IOError, HttpStatus, Open m.fl. - ingenting!
Og når jeg har haft kigget i serverloggen er det som om at den side der gemmer aldrig er blevet kaldt, som om at requesten simpelthen er forsvundet i den blå luft.
Med andre ord, så sidder brugeren bare og venter i en uendelighed uden at der sker noget, hvilket er meget langt fra optimalt.

Jeg har haft prøvet alle mulige forskellige måder at sende requesten på - binary, base64 encoded, GET, POST og meget andet - men altsammen med samme resultat, nogen gange fejler det bare på Mac+Safari når der sendes mange data.

Så, for at slå to fluer med et smæk, har jeg lavet min egen klasse, som både er i stand til at give feedback undervejs såvel som at eliminere problemet med Mac+Safari.
Ganske enkelt gør klassen det, at den deler billedet op i mange små bidder, som den sender én af gangen, og for hver sendt bid sender den en event, så man kan lave en nydelig upload progress.

På serveren er der så et php-script som laver en midlertidig fil, hvor den løbende gemmer de enkelte bidder, og når den sidste bid er modtaget, slettes den midlertidige fil og en rigtig billedfil, i dette tilfælde png, genereres.

Alt i alt, betyder det at billedet kan sendes med denne smule kode:

var pngStream:ByteArray = PNGEncoder.encode(pngSource);

var url:String = "http://www.server,dj/save_picture.php";
var filename:String = "mitbillede";
var steps:int = 20; //Antallet af bidder som billedet deles op i

var pictureSender:PictureSender = new PictureSender(url, filename, pngStream, steps);
pictureSender.addEventListener(pictureSender.UPLOAD_PROGRESS, uploadProgress);
pictureSender.addEventListener(Event.COMPLETE, loaderComplete);
pictureSender.send();

public function uploadProgress(_e:ProgressEvent) {
	trace("Upload " + String(Math.round((_e.bytesLoaded / steps) * 100)) + "%");
}

public function loaderComplete(_e:Event):void {
	trace("upload complete");
}

Jeg har samlet det nødvendige, både ActionScript og php, i en zip-fil som alle er velkomne til at downloade og bruge som de har lyst:
PictureSender.zip

Værd at bemærke er dog, at det er noget jeg hurtigt har bikset sammen til mig selv, så det kan helt sikkert både struktureres og dokumenteres bedre, men håber det kan bruges alligevel.

Note: Normalt bruger man FileReference når der tales om upload af filer, men da der i dette tilfælde er tale om data som Flash har genereret, frem for en fysisk fil fra brugerens harddisk, så kan den ikke bruges.


ActionScript 3 - LoadVars = URLLoader

Kategori: Tips og tricks | Kommentarer (2)
Gemt: 2007-11-22 16:19


Et af de mest benyttede objekter i ActionScript 2 har givetvis været LoadVars, den universelle måde til at sende og modtage data.
I ActionScript 3 er den blevet erstattet med URLLoader (og lidt forskelligt andet), og derfor synes jeg lige den var et indlæg hver.

En typisk LoadVars kunne se sådan her ud:

lV = new LoadVars();
lV.var1 = "hej";
lV.var = 3;
lV.onLoad = function() {
trace("gør noget");
}
lV.sendAndLoad("http://www.noget.dk/modtagdata.php", lV, "GET");

Helt så simpelt er det ikke mere, men til gengæld har man nu en endnu højere grad af kontrol og flere muligheder.

Har kommenteret koden, så burde være forståeligt:

//Klassen som loader alt i AS3
var loader:URLLoader = new URLLoader();

//Hvilken funktion skal kaldes når loading er complete
loader.addEventListener(Event.COMPLETE, loadComplete);

//Requesten er klassen som definerer, ja nemlig, det der skal requestes - først urlen som skal kaldes
var request:URLRequest = new URLRequest("http://www.noget.dk/modtagdata.php")

//Hvilke variabler skal sendes med
var variables:URLVariables = new URLVariables();
variables.var1 = "hej";
variables.var2 = 4;
request.data = variables;

//Hvilken metode skal bruges
request.method = URLRequestMethod.GET;

//I LoadVars var der ofte problemer med at Flash cachede resultatet, hvorfor man tit tilføjede et tilfældigt nr.
//Nu kan det løses helt simpelt ved at tilføje en header
var header:URLRequestHeader = new URLRequestHeader("pragma", "no-cache");
request.requestHeaders.push(header);

//Start loading
loader.load(request);

//Funktionen som kaldes når load er færdig
function loadComplete(e:Event):void {
//Tracer det tekst som siden man kalder skriver ud
trace(e.target.data);
}

Man kan sige meget om ActionScript 3, men når først man har koden foran sig, så er det temmelig logisk hvad der sker hvorfor.

Det svære er nogen gange at få luret præcis hvor man starter, men håber at eksemplet her er med til at hjælpe dig lidt igang :-)

NB: Yes, bloggen her er enormt ringe til at vise kode, er noget der står på listen til en ny version.