SharedObject - optimalizace výkonu

Březen 29th, 2009

V jednom z dokončovaných projektů jsem zjistil zbytečnou zátěž procesoru, která na první pohled neměla žádný rozumný důvod. Profilování ve Flex Builderu také nehlásilo nic neobvyklého a tak musela na řadu přijít klasická metoda reverzního odhalování kritického místa, kterým se nakonec ukázalo použití třídy SharedObject.

Problémem se ukázalo časté dotazování na uložená data, při kterém se v každém novém dotazu vytvářela nová instance třídy SharedObject. Došel jsem k celkem zajímavým výsledkům, kdy například dva dotazy najednou zabraly zhruba 16ms, čtyři už asi 31ms atd. To je pro chod běžných aplikací nepřijatelné. Naštěstí je řešení vcelku jednoduché - nevytvářet pokaždé novou instanci, ale využívat jednu, předem vytvořenou.

Data do SharedObjectu vypadají takto:

var sharedObj:SharedObject = SharedObject.getLocal("myData");
sharedObj.data.nfo = "text";
sharedObj.flush();

A problémový skript pak vypadá následovně:

function getSoData():String {
    var sObj:SharedObject = SharedObject.getLocal("myData");
    var str:String = sObj.data.nfo;
    return str;
}
function testSharedData(count:uint):void {
    var dat:Date = new Date();
    var ms:Number = dat.getTime();
    for (var i:uint=0; i<count; i++) {
        trace(getSoData());
    }
    var dat2:Date = new Date();
    var dif:Number = dat2.getTime()-ms;
    trace("Čas výpočtu: "+dif+"ms");
}
testSharedData(10);

Po spuštění deseti dotazů na SharedObject třídu se dostaneme k délce trvání zhruba 63ms

Upravená funkce pro získání dat pak využívá předem vytvořenou instanci SharedObject třídy a na výkonu je to citelně znát, uvedený čas je 0ms:

var sharedObj:SharedObject = SharedObject.getLocal("myData");
function getSoData():String {
    var str:String = sharedObj.data.nfo;
    return str;
}

Test bezpečnosti SWF souborů

Březen 25th, 2009

Od společnosti HP máme čerstvě k dispozici užitečný program SWFScan, díky kterému můžeme otestovat SWF soubory a objevit tak případné prohřešky vůči bezpečnostním doporučením pro vývoj flashových aplikací. Varování se nejčastěji týká debug verzí aplikací, které bychom neměli vůbec pouštět do světa, stejně tak odstranění trace funkcí je žádoucí. Aplikace přináší souhrn veškerých odkazů a adres, které se ze SWF souboru dají vyčíst, což nám může také výrazně pomoci. Poslední zajímavou funkcí je možnost exportu ActionScriptu do *.as souboru. Určitě tak tenhle prográmek stojí za vyzkoušení.

Digest mismatch with RSL

Březen 24th, 2009

Při používání RSL (Runtime Shared Library) ve Flex Builderu jsem po aktualizaci zjistil nekompatibilitu s novou verzí Flex 3.2 SDK:

V nastavení kompileru, respektive u Library Path zůstal odkaz na starou verzi SWF+SWZ knihoven, takže při exportu došlo k chybnému načtení. Jednoduché řešení spočívá v doplnění poslední verze knihoven framework_3.2.0.3958 , které najdeme v balíčku Flex 3.2 SDK

Silverlight na desktopu

Březen 20th, 2009

A zase ten Silverlight :) Je ale nutné znát co nejlépe možnosti, výhody a nevýhody konkurenční technologie, takže do toho. Dnes na živě.cz vyšla zprávička o tom, že SL bude možné pouštět i lokálně, bez nutnosti nějakého dodatečného přehrávače (na rozdíl od AIRu).  I v článečku na živě.cz se zmiňují, že se jedná o přímou konkurenci k Adobe AIRu. PR informace od MS ohledně jejich nové technologie už beru raději s rezervou, takže jsem se porozhlédnul i jinde: http://blog.digitalbackcountry.com/2009/03/differences-between-silverlight-out-of-browser-experience-and-air/ Těmto zdrojům věřím o poznání více, takže shrnuto podtrženo, přímá konkurence pro AIR to nebude, tím jsou desktopové produkty WPF Spíše bych to viděl jako konkurenci pro flashové aplikace spuštěné v rámci StandAlone FlashPlayeru. Stále totiž vše běží v rámci bezpečnostního prostoru webového prohlížeče, bez možností přístupu na disk, práci se soubory, využití databáze...

validateNow() ve Flexu

Březen 19th, 2009

Vložení komponenty v žádném případě neznamená, že lze ihned přistoupit k jejím vlastnostem, které plynou z její následné vizualizace a to především velikosti. Příkaz trace v tomto případě vrátí nulovou hodnotu:

var newBtn:Button = new Button();
newBtn.label = "Tlačítko";
container.addChild(newBtn);
trace("šířka: "+newBtn.height);//vrací nulovou hodnotu

Je to z toho důvodu, že vykreslení a aktualizace vlastností komponenty se děje postupně až při nejbližší "příležitosti" - novému renderování scény. Pomocí metody validateNow() lze spustit okamžitou aktualizaci komponenty, takže pak už je možné pracovat s její velikostí:

var newBtn:Button = new Button();
newBtn.label = "Tlačítko";
container.addChild(newBtn);
newBtn.validateNow();
trace("šířka: "+newBtn.height);
//vrátí hodnotu 22
//- defaultní u Button komponent

Pokud ovšem potřebujeme pracovat i se změnou velikosti komponenty, do které je například nové tlačítko vloženo, je nutné zavolat metodu validateNow() pro nadřazenou komponentu. Obecně je ale vždy vhodnější volat uvedenou metodu vždy z komponenty, která je nadřazená té, u které chceme okamžitě zjistit nové rozměry. Pro nadřazenou komponentu "container" z příkladu by tedy bylo vhodnější použít příkaz:

var newBtn:Button = new Button();
newBtn.label = "Tlačítko";
container.addChild(newBtn);
container.parent.validateNow();
trace("šířka: "+container.height);//vrátí
//novou výšku nadřazené komponenty containe

Otáčení mimo střed objektu

Březen 15th, 2009

Třída MatrixTransformer je poměrně užitečná, pokud potřebujeme například manipulovat s objekty (měnit velikost, zkosení, rotaci apod.)  přes Matrix třídu. Jednou z výborných metod je pak rotateAroundExternalPoint, která nám umožňuje rotaci objektu podle libovolného bodu na scéně. Běžná rotace totiž probíhá přesně podle souřadnicového středu objektu, což může být občas prolém. Následující skript ukazuje využití této metody (po kliknutí se objekt bude otáčet podle nového bodu):

import fl.motion.MatrixTransformer;
var xPoint:int = 200;
var yPoint:int = 200;
var angle:int = 5;
function changeTrasnfPoint(evt:Event):void {
    xPoint = this.stage.mouseX;
    yPoint = this.stage.mouseY;
}
function rotate(evt:Event):void {
    var matrix:Matrix = obj_mc.transform.matrix;
    MatrixTransformer.rotateAroundExternalPoint(matrix,
xPoint,yPoint,angle);
    obj_mc.transform.matrix = matrix;
}
this.addEventListener( Event.ENTER_FRAME,rotate);
this.stage.addEventListener(MouseEvent.MOUSE_DOWN,
changeTrasnfPoint);

Flex - kulaté rohy komponent

Březen 11th, 2009

Chvilička zkoušení, abych zjistil, že kulaté rohy pro Canvas a HBox/VBox komponenty nejsou jenom díky stylu cornerRadius, ale že se k tomu musí doplnit i styl pro ohraničení komponenty, tedy borderStyle:

Canvas
{
backgroundColor: #FFFFFF;
borderColor: #FFFFFF;
borderStyle: solid;
borderThickness: 5;
cornerRadius: 10;
}

Hromadná oprava XML

Březen 9th, 2009

Při práci s XML daty v ActionScriptu 3.0 se moc nezapotíme (vyjma opomenutí data binding, ale o tom jindy). Pokud porovnám práci (spíše trápení) s XMLkem v AS2, tak v AS3 je to doslova hraní.

V případě, že do vstupních XML dat aplikace může zasáhnout lidský faktor, může se stát, že některé hodnoty nedostaneme v požadované formě, jak očekáváme.  Klasickým příkladem může být zadávání nepovolených znaků, textu místo čísel a někdy vadí i nesprávné kombinování velkých a malých písmen.

Pokud potřebujeme překontrolovat vstupní data, jednou z možností je odfiltrování konkrétního elementu následujícím způsobem:

var pomList:XMLList = dataXML..xmlElement;

Do XMLList objektu se vloží pouze elementy xmlElement ze zdrojového xml objektu dataXML. Nezáleží, kde jsou umístěné, pomocí dvoutečkové syntaxe získáme zpět opravdu všechny, které se v XML datech vyskytují.

V dalším kroku už stačí projít prvky XMLListu a provést s nimi požadovanou kontrolu. Protože jsou do prvků XMLListu vloženy přímé reference na zdrojové XML elementy, změna se projeví ve zdrojovém XML objektu. Zmíněné zvětšení vstupních dat na velká písmena pak může vypadat takto:

var pomList:XMLList = dataXML..xmlElement;
for (var s:uint=0; s<pomList.length(); s++) {
if (String(pomList[s]).length>0) {
pomList[s] = String(pomList[s]).toUpperCase();
}
}

Symbol Graphic a vložené MovieClipy

Březen 5th, 2009

Symboly typu Graphic moc nevyužívám a možná i proto mě poměrně zaujalo zjištění, jak se chovají na scéně. Graphic symbol nemůže mít název instance, proto jej nelze v AS2 ovládat (v AS3 to samozřejmě jde), ale co se stane, když do něj ručně vložíme (ve Flashi CS3/4) nějaký aktivní prvek (tlačítko, MovieClip) a odkážeme se na _parent objekt?  Scéna vypadá takto:

Pokud se v MovieClipu objekt_2 odkážeme na nadřazený objekt, dostaneme zpět referenci na objekt_1. Jak to bude vypadat z opačného směru při parsování pomocí AS3?:

var num:uint = objekt_1.numChildren;
trace("num: "+num);
for (var i:uint=0; i<num; i++) {
    trace(obj_mc.getChildAt(i));
    trace(obj_mc.getChildAt(i).name);
}

Výpis v output okně:

num: 2
[object Shape]
instance1
[object MovieClip]
objekt_2

Je tak potvrzeno, že pokud vložíme do Graphic symbolu jiný objekt, sice je jakoby uvnitř Graphic symbolu, ale reálně je na stejné úrovni jako samotný symbol Graphics. Je to celkem pochopitelné, protože Shape objekty nemohou obsahovat vložené objekty z DisplayObject třídy. Pouze prostředí Flashe CS3/4 může díky možnosti vkládání objektů do těchto Graphics symbolů přinášet trochu nejasností při jejich zpracování pomocí ActionScriptu.

List komponenta a pořadí vybraných položek

Březen 4th, 2009

Při použití List komponenty, u které máme povolen výběr více položek přes atribut allowMultipleSelection="true", nám vrací pole vybraných prvků vždy v tom pořadí, ve kterém provedl uživatel výběr. V některých případech ale potřebujeme získat seznam vybraných prvků přesně v tom pořadí, v jakém jsou umístěn v komponentě, bez ohledu na způsob výběru. Řešením je přistoupení k vybraným objektů pomocí atributu selectedIndices, který vrací indexy vybraných položek (opět v pořadí dle volby uživatele). Před jejich dalším zpracováním stačí už jenom provést seřazení v poli:

var arr:Array = komponentaList.selectedIndices;
trace("Původní pořadí prvků
podle výběru uživatele: "+arr);
arr.sort(Array.NUMERIC|Array.DESCENDING);
trace("Nové pořadí prvků podle
jejich umístění v komponentě: "+arr);