Caching bitmap

Utilizzate la funzione di caching bitmap per il contenuto vettoriale complesso, nei casi appropriati.

La funzione di caching bitmap consente di ottenere una buona ottimizzazione. Questa funzione provvede a memorizzare un oggetto vettore nella cache, ne esegue il rendering come bitmap internamente e utilizza la bitmap così ottenuta per il rendering. Il risultato può essere un miglioramento significativo delle prestazioni di rendering, che tuttavia può avvenire a spese della quantità di memoria utilizzata. Utilizzate la funzione di caching bitmap per il contenuto vettoriale complesso, ad esempio gradienti o testi sofisticati.

L'attivazione del caching bitmap per un oggetto animato che contiene grafica vettoriale complessa (ad esempio testo o gradienti) consente di migliorare le prestazioni. Se tuttavia è attivata la memorizzazione delle bitmap nella cache per un oggetto di visualizzazione, quale un clip filmato con la linea temporale in esecuzione, otterrete il risultato opposto. Per ogni fotogramma il runtime deve aggiornare la bitmap nella cache e ridisegnarla sullo schermo, richiedendo molti cicli della CPU. La funzione di caching bitmap è vantaggiosa solo quando la bitmap nella cache può essere generata una sola volta e quindi utilizzata senza che sia necessario aggiornarla.

Se attivate il caching bitmap per un oggetto Sprite, quest'ultimo può essere spostato senza che il runtime debba rigenerare la bitmap nella cache. La modifica delle proprietà x e y dell'oggetto non ne causa la rigenerazione. Tuttavia, qualsiasi tentativo di ruotare o ridimensionare l'oggetto, oppure di modificarne il valore alfa, fa sì che il runtime rigeneri la bitmap nella cache peggiorando, di conseguenza, le prestazioni.

Nota: la proprietà DisplayObject.cacheAsBitmapMatrix disponibile in AIR e in Packager per iPhone non è soggetta a questa limitazione. Utilizzando la proprietà cacheAsBitmapMatrix potete ruotare, modificare in scala, inclinare e cambiare il valore alfa di un oggetto di visualizzazione senza attivare la rigenerazione della bitmap.

Una bitmap memorizzata nella cache può utilizzare più memoria di una normale istanza di clip filmato. Per esempio, se il clip filmato sullo stage misura 250 x 250 pixel, esso utilizza circa 250 KB se è memorizzato nella cache oppure solo 1 KB senza il caching.

L'esempio seguente è relativo a un oggetto Sprite che contiene l'immagine di una mela. La classe seguente è associata al simbolo della mela:

package org.bytearray.bitmap 
{     
    import flash.display.Sprite; 
    import flash.events.Event; 
     
    public class Apple extends Sprite 
    { 
        private var destinationX:Number; 
        private var destinationY:Number; 
         
        public function Apple () 
        { 
            addEventListener(Event.ADDED_TO_STAGE,activation); 
            addEventListener(Event.REMOVED_FROM_STAGE,deactivation);     
        } 
         
        private function activation(e:Event):void  
        { 
            initPos();     
            addEventListener (Event.ENTER_FRAME,handleMovement);     
        } 
         
        private function deactivation(e:Event):void  
        { 
            removeEventListener(Event.ENTER_FRAME,handleMovement);     
        } 
         
        private function initPos():void 
        { 
            destinationX = Math.random()*(stage.stageWidth - (width>>1)); 
            destinationY = Math.random()*(stage.stageHeight - (height>>1)); 
        } 
         
        private function handleMovement(e:Event):void  
        { 
            x -= (x - destinationX)*.5; 
            y -= (y - destinationY)*.5; 
             
            if (Math.abs(x - destinationX) < 1 && Math.abs(y - destinationY) < 1) 
                initPos(); 
        } 
    } 
}

Il codice utilizza la classe Sprite anziché la classe MovieClip perché non è necessaria una linea temporale per ciascuna mela. Per ottenere prestazioni ottimali, usate oggetti il più possibile "leggeri". Quindi, viene creata un'istanza della classe con il codice seguente:

import org.bytearray.bitmap.Apple; 
 
stage.addEventListener(MouseEvent.CLICK,createApples); 
stage.addEventListener(KeyboardEvent.KEY_DOWN,cacheApples); 
 
const MAX_NUM:int = 100; 
var apple:Apple; 
var holder:Sprite = new Sprite(); 
 
addChild(holder); 
 
function createApples(e:MouseEvent):void 
{ 
    for (var i:int = 0; i< MAX_NUM; i++) 
    { 
        apple = new Apple(); 
         
        holder.addChild(apple); 
    } 
} 
 
function cacheApples(e:KeyboardEvent):void 
{ 
    if (e.keyCode == 67) 
    { 
        var lng:int = holder.numChildren; 
         
        for (var i:int = 0; i < lng; i++) 
        { 
            apple = holder.getChildAt (i) as Apple; 
             
            apple.cacheAsBitmap = Boolean(!apple.cacheAsBitmap); 
        } 
    } 
}

Quando l'utente fa clic sul mouse, le mele vengono create senza memorizzazione nella cache. Quando l'utente preme il tasto C (codice tasto 67), i vettori delle mele vengono memorizzati nella cache come bitmap e visualizzati sullo schermo. Questa tecnica migliora sensibilmente le prestazioni di rendering, sia sul desktop che sui dispositivi mobili, quando la CPU è lenta.

D'altra parte, benché la funzione di caching bitmap garantisca prestazioni di rendering migliori, essa può anche consumare rapidamente grandi quantità di memoria. Non appena un oggetto viene memorizzato nella cache, la sua superficie viene catturata come bitmap trasparente e memorizzata in memoria, come mostra il diagramma seguente:

L'oggetto e la sua bitmap di superficie memorizzati in memoria

Flash Player 10.1 e AIR 2.5 ottimizzano l'uso della memoria adottando lo stesso approccio descritto in Filtri e scaricamento dinamico delle bitmap . Se un oggetto di visualizzazione memorizzato nella cache è nascosto oppure fuori schermo, la relativa bitmap in memoria viene liberata se non viene utilizzata per un certo intervallo di tempo.

Nota: se la proprietà opaqueBackground dell'oggetto di visualizzazione è impostata su un colore, specifico, il runtime considera l'oggetto di visualizzazione come opaco. Quando è utilizzata con la proprietà cacheAsBitmap , il runtime crea in memoria una bitmap non trasparente a 32 bit. Il canale alfa viene impostato su 0xFF, per migliorare le prestazioni, dal momento che non è richiesta alcuna trasparenza per disegnare la bitmap sullo schermo. Evitando di utilizzare la fusione alfa, si ottiene un rendering ancora più veloce. Se la profondità corrente dello schermo è limitata a 16 bit, la bitmap in memoria viene memorizzata come immagine a 16 bit. L'uso della proprietà opaqueBackground non attiva implicitamente il caching bitmap.

Per risparmiare memoria, utilizzate la proprietà cacheAsBitmap e attivatela per ogni oggetto di visualizzazione diverso dal contenitore. L'attivazione del caching bitmap sul contenitore produrrebbe una bitmap finale molto più grande in memoria, creando una bitmap trasparente con dimensioni di 211 x 279 pixel. L'immagine utilizza circa 229 KB di memoria:

Visualizzazione dell’elemento grafico a dimensioni intere
Attivazione del caching bitmap sul contenitore

Inoltre, memorizzando il contenitore nella cache rischiate di aggiornare l'intera bitmap in memoria, se una mela qualsiasi inizia a muoversi su un fotogramma. L'attivazione del caching bitmap sulle singole istanze determina la memorizzazione nella cache di sei superfici di 7 KB, con un consumo totale di soli 42 KB di memoria:

Visualizzazione dell’elemento grafico a dimensioni intere
Attivazione del caching bitmap sulle istanze

Con l'accesso a ogni istanza della mela tramite l'elenco di visualizzazione e la chiamata del metodo getChildAt() , i riferimenti vengono memorizzati in un oggetto Vector per consentire un accesso più facile:

import org.bytearray.bitmap.Apple; 
 
stage.addEventListener(KeyboardEvent.KEY_DOWN, cacheApples); 
 
const MAX_NUM:int = 200; 
var apple:Apple; 
var holder:Sprite = new Sprite(); 
 
addChild(holder); 
 
var holderVector:Vector.<Apple> = new Vector.<Apple>(MAX_NUM, true); 
 
for (var i:int = 0; i< MAX_NUM; i++) 
{ 
    apple = new Apple(); 
     
    holder.addChild(apple); 
     
    holderVector[i] = apple; 
} 
 
function cacheApples(e:KeyboardEvent):void 
{ 
    if (e.keyCode == 67) 
    { 
        var lng:int = holderVector.length 
         
        for (var i:int = 0; i < lng; i++) 
        { 
            apple = holderVector[i]; 
             
            apple.cacheAsBitmap = Boolean(!apple.cacheAsBitmap); 
        } 
    } 
}

Tenete presente che la funzione di caching bitmap migliora il rendering se il contenuto memorizzato nella cache non è ruotato o ridimensionato, né modificato su ciascun fotogramma. Al contrario, in caso di trasformazioni diverse dalla traslazione sugli assi x e y, il rendering non viene migliorato. In questi casi, Flash Player aggiorna la copia della bitmap nella cache per ogni trasformazione applicata all'oggetto di visualizzazione. L'aggiornamento della copia nella cache può determinare un uso intensivo della CPU, prestazioni rallentate e un consumo elevato della batteria. Di nuovo, la proprietà cacheAsBitmapMatrix in AIR o in Packager per iPhone non è soggetta a questa limitazione.

Il codice seguente modifica il valore alfa del metodo di movimento, cambiando l'opacità della mela su ciascun fotogramma:

private function handleMovement(e:Event):void  
{ 
        alpha = Math.random(); 
        x -= (x - destinationX)*.5; 
        y -= (y - destinationY)*.5; 
             
        if (Math.abs(x - destinationX) < 1 && Math.abs(y - destinationY) < 1) 
            initPos(); 
}

L'uso del caching bitmap causa un rallentamento delle prestazioni. La modifica del valore alfa obbliga il runtime ad aggiornare la bitmap nella cache a ogni modifica del valore.

I filtri fanno riferimento alle bitmap che vengono aggiornate ogni volta che l'indicatore di riproduzione di un clip filmato nella cache si sposta. Di conseguenza, l'uso di un filtro imposta automaticamente la proprietà cacheAsBitmap su true . La figura seguente illustra un clip filmato animato:

Clip filmato animato

Evitate di utilizzare i filtri sui contenuti animati, perché possono causare problemi di prestazioni. Nella figura seguente, il designer ha aggiunto un filtro ombra esterna:

Clip filmato animato con filtro Ombra esterna

Di conseguenza, se la linea temporale di un clip filmato è in corso di riproduzione, la bitmap deve essere rigenerata. Anche se il contenuto viene modificato in qualsiasi modo che non sia una semplice trasformazione x o y, la bitmap deve essere rigenerata. Per ogni fotogramma il runtime deve ridisegnare la bitmap, con il risultato che la CPU è sottoposta a un carico di lavoro maggiore, le prestazioni peggiorano e l'autonomia della batteria diminuisce.

Nelle seguenti esercitazioni video, PaulTrani fornisce degli esempi che mostrano come usare Flash Professional e ActionScript per ottimizzare la grafica utilizzando le bitmap: