Bitmap-Zwischenspeicherung

Verwenden Sie das Zwischenspeichern von Bitmaps für komplexen Vektorinhalt, sofern geeignet.

Eine gute Optimierung lässt sich durch das Zwischenspeichern von Bitmaps erzielen. Dabei wird ein Vektorobjekt im Cache zwischengespeichert und intern als Bitmap gerendert. Diese Bitmap wird dann zum Rendern verwendet. Die Renderleistung kann auf diese Weise ganz erheblich verbessert werden, der Nachteil ist jedoch, dass der Arbeitsspeicher stark beansprucht werden kann. Verwenden Sie das Zwischenspeichern von Bitmaps für komplexen Vektorinhalt, wie beispielsweise komplexe Verläufe oder Text.

Das Aktivieren der Bitmap-Zwischenspeicherung für ein animiertes Objekt mit komplexen Vektorgrafiken (wie Text oder Farbverläufe) verbessert die Leistung. Wenn die Bitmap-Zwischenspeicherung jedoch für ein Anzeigeobjekt aktiviert ist, dessen Zeitleiste abgespielt wird (wie bei einem Movieclip), tritt das Gegenteil ein. In diesem Fall muss die Laufzeitumgebung die zwischengespeicherte Bitmap bei jedem Bild aktualisieren und auf dem Bildschirm neu zeichnen, was die CPU stark beansprucht. Die Bitmap-Zwischenspeicherung bietet nur dann Vorteile, wenn die zwischengespeicherte Bitmap nur einmal erstellt und dann nicht mehr aktualisiert werden muss.

Wenn Sie die Bitmap-Zwischenspeicherung für ein Sprite-Objekt aktivieren, kann das Objekt verschoben werden, ohne dass die Laufzeitumgebung die zwischengespeicherte Bitmap neu generiert. Durch Ändern der Eigenschaften x und y wird das Objekt nicht neu generiert. Wenn jedoch versucht wird, das Objekt zu drehen, zu skalieren oder seinen Alphawert zu ändern, generiert die Laufzeitumgebung die zwischengespeicherte Bitmap neu, was sich negativ auf die Leistung auswirkt.

Hinweis: Die DisplayObject.cacheAsBitmapMatrix -Eigenschaft, die in AIR und im Packager for iPhone verfügbar ist, hat diese Einschränkung nicht. Indem Sie die cacheAsBitmapMatrix -Eigenschaft verwenden, können Sie den Alphawert eines Objekts drehen, skalieren, neigen und ändern, ohne dass die Bitmap neu generiert wird.

Eine zwischengespeicherte Bitmap belegt möglicherweise mehr Arbeitsspeicher als eine reguläre Movieclip-Instanz. Beispielsweise belegt ein Movieclip, der auf der Bühne eine Größe von 250 x 250 Pixel hat, im Cache ca. 250 KB anstelle von regulär 1 KB.

Das folgende Beispiel betrifft ein Sprite-Objekt, das ein Bild eines Apfels enthält. Die folgende Klasse wird an das Symbol des Apfels angefügt:

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(); 
        } 
    } 
}

In diesem Code wird die Sprite-Klasse anstelle der MovieClip-Klasse verwendet, da keine separate Zeitleiste für jeden Apfel erforderlich ist. Verwenden Sie das Objekt, das am wenigsten Ressourcen belegt, um eine optimale Leistung zu erreichen. Als Nächstes wird die Klasse mit dem folgenden Code instanziiert:

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); 
        } 
    } 
}

Wenn der Benutzer mit der Maus klickt, werden die Äpfel ohne Zwischenspeicherung erstellt. Wenn der Benutzer die Taste „C“ drückt (Tastencode 67), werden die Vektoren der Äpfel als Bitmaps im Cache zwischengespeichert und auf dem Bildschirm angezeigt. Mit dieser Technik kann die Renderleistung bei einer langsamen CPU sowohl auf Desktop- als auch auf Mobilgeräten deutlich verbessert werden.

Dabei ist jedoch zu beachten, dass das Zwischenspeichern von Bitmaps zwar die Renderleistung verbessert, andererseits aber große Mengen Arbeitsspeicher in Anspruch nehmen kann. Sobald ein Objekt im Cache zwischengespeichert wird, wird seine Oberfläche als transparente Bitmap erfasst und im Arbeitsspeicher gespeichert, wie in der folgenden Abbildung gezeigt:

Objekt und seine Oberflächen-Bitmap im Arbeitsspeicher

Flash Player 10.1 und AIR 2.5 optimieren die Nutzung des Arbeitsspeichers mit demselben Ansatz, der unter Filter und dynamisches Entladen von Bitmaps beschrieben ist. Wenn ein zwischengespeichertes Anzeigeobjekt ausgeblendet oder offscreen ist, wird der von der Bitmap belegte Arbeitsspeicher freigegeben, nachdem die Bitmap eine Weile nicht verwendet wurde.

Hinweis: Wenn die opaqueBackground -Eigenschaft des Anzeigeobjekts auf eine bestimmte Farbe eingestellt ist, geht die Laufzeitumgebung davon aus, dass das Anzeigeobjekt undurchsichtig ist. Bei Verwendung mit der cacheAsBitmap -Eigenschaft erstellt die Laufzeitumgebung eine undurchsichtige 32-Bit-Bitmap im Arbeitsspeicher. Der Alphakanal ist auf 0xFF eingestellt, was die Leistung verbessert, da keine Transparenz erforderlich ist, um die Bitmap auf dem Bildschirm zu zeichnen. Durch die Vermeidung der Alpha-Mischung wird das Rendern noch schneller. Wenn die aktuelle Bildschirmtiefe auf 16 Bit beschränkt ist, wird die Bitmap als 16-Bit-Bild im Arbeitsspeicher gespeichert. Durch Verwendung der opaqueBackground -Eigenschaft wird die Bitmap-Zwischenspeicherung nicht implizit aktiviert.

Um Arbeitsspeicher einzusparen, empfiehlt es sich, die cacheAsBitmap -Eigenschaft zu verwenden und für jedes Anzeigeobjekt einzeln anstatt für den Container zu aktivieren. Wenn die Bitmap-Zwischenspeicherung für den Container aktiviert wird, ist die endgültige Bitmap im Arbeitsspeicher wesentlich größer, da eine transparente Bitmap mit den Abmessungen 211 x 279 Pixel erstellt wird. Das Bild belegt ungefähr 229 KB Arbeitsspeicher.

Grafik in Originalgröße anzeigen
Aktivieren der Bitmap-Zwischenspeicherung für den Container

Außerdem birgt das Zwischenspeichern des Containers das Risiko, dass die ganze Bitmap im Arbeitsspeicher aktualisiert wird, wenn ein Apfel sich in einem Bild bewegt. Wenn die Bitmap-Zwischenspeicherung für die einzelnen Instanzen aktiviert wird, werden sechs Oberflächen mit jeweils 7 KB im Arbeitsspeicher zwischengespeichert, also insgesamt nur 42 KB.

Grafik in Originalgröße anzeigen
Aktivieren der Bitmap-Zwischenspeicherung für Instanzen

Wenn Sie auf jede Apfel-Instanz über die Anzeigeliste zugreifen und die getChildAt() -Methode aufrufen, werden Verweise in einem Vector-Objekt gespeichert, was den Zugriff vereinfacht:

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); 
        } 
    } 
}

Beachten Sie, dass die Bitmap-Zwischenspeicherung das Rendern verbessert, wenn der zwischengespeicherte Inhalt nicht in jedem Bild gedreht, skaliert oder geändert wird. Bei anderen Transformationen als der Verschiebung entlang der x- und y-Achsen wird das Rendern jedoch nicht verbessert. In diesen Fällen aktualisiert Flash Player die zwischengespeicherte Kopie der Bitmap für jede Transformation des Anzeigeobjekts. Die Aktualisierung der zwischengespeicherten Kopie kann zu einer hohen CPU-Auslastung, einer schlechteren Leistung und zu einer hohen Akkunutzung führen. Wiederum gilt diese Einschränkung nicht für die cacheAsBitmapMatrix -Eigenschaft, die in AIR und im Packager for iPhone zur Verfügung steht.

Der folgende Code ändert den Alphawert in der Verschiebungsmethode, wodurch die Deckkraft des Apfels in jedem Bild geändert wird:

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(); 
}

Die Verwendung der Bitmap-Zwischenspeicherung führt zu Leistungseinbußen. Wegen des geänderten Alphawertes muss die Laufzeitumgebung die im Arbeitsspeicher zwischengespeicherte Bitmap bei jeder Änderung des Alphawertes aktualisieren.

Filter benötigen Bitmaps, die immer aktualisiert werden, wenn der Abspielkopf eines zwischengespeicherten Movieclips sich bewegt. Bei Verwendung eines Filters wird die cacheAsBitmap -Eigenschaft deshalb automatisch auf true gesetzt. Die folgende Abbildung zeigt einen animierten Movieclip:

Animierter Movieclip

Vermeiden Sie Filter für animierte Inhalte, da dies zu Leistungsproblemen führen kann. In der folgenden Abbildung wurde ein Schlagschatten-Filter hinzugefügt:

Animierter Movieclip mit Schlagschatten-Filter

Deshalb muss die Bitmap neu generiert werden, wenn die Zeitleiste innerhalb des Movieclips abgespielt wird. Die Bitmap muss auch neu generiert werden, wenn der Inhalt auf eine Weise geändert wird, bei der es sich nicht um eine einfache x- oder y-Transformation handelt. Bei jedem Bild muss die Laufzeitumgebung die Bitmap neu zeichnen. Dies erfordert mehr CPU-Ressourcen, beeinträchtigt die Leistung und beansprucht den Akku stärker.

Paul Trani stellt in den folgenden Schulungsvideos Beispiele für die Verwendung von Flash Professional und ActionScript zur Optimierung von Grafiken mit Bitmaps bereit: