在适当的时候,对复杂的矢量内容使用位图缓存功能。
使用位图缓存功能可实现良好的优化。此功能缓存矢量对象,将其作为位图在内部呈现,并使用该位图进行呈现。此结果会显著提高呈现的性能,但需要占用大量内存。针对复杂的矢量内容使用位图缓存功能,如复杂渐变或文本。
为包含复杂的矢量图形(例如文本或渐变)的动画对象打开位图缓存可提高性能。但是,如果在显示对象(如播放其时间轴的影片剪辑)中启用了位图缓存,您将获得相反的效果。在各个帧上,运行时必须更新缓存的位图,然后在屏幕上重绘该位图,这一过程需要许多 CPU 周期。仅当缓存的位图可以一次生成,且随后无需更新即可使用时,才适合使用位图缓存功能。
为 Sprite 对象打开位图缓存后,移动该对象不会使运行时重新生成缓存的位图。更改对象的
x
和
y
属性不会导致重新生成。然而,任何试图旋转、缩放对象或更改其 alpha 值的行为都将导致运行时重新生成缓存的位图,从而降低性能。
注:
AIR 和 Packager for iPhone 中提供的
DisplayObject.cacheAsBitmapMatrix
属性没有此限制。通过使用
cacheAsBitmapMatrix
属性,您可以旋转、缩放、倾斜显示对象以及更改其 Alpha 值,而不触发重新生成位图。
缓存位图占用的内存大于常规影片剪辑实例。例如,如果舞台上的影片剪辑为 250 x 250 像素,缓存它可能会使用 250 KB 内存,而未缓存它只需 1 KB。
以下示例使用一个包含苹果图像的 Sprite 对象。以下类将附加到苹果符号:
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();
}
}
}
以上代码使用的是 Sprite 类而不是 MovieClip 类,因为并非每个苹果都需要时间轴。为了获得最佳性能,请尽可能使用最轻型的对象。接下来,将使用以下代码实例化此类:
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);
}
}
}
当用户单击鼠标时,将创建苹果,而不需要进行缓存。当用户按下 C 键(键代码为 67),苹果矢量将作为位图缓存并显示在屏幕上。当 CPU 较慢时,此技术可显著提高台式机和移动设备上的呈现性能。
但是,虽然使用位图缓存功能可以提高呈现性能,但也会快速占用大量内存。缓存对象后,其表面将捕获为透明位图并存储在内存中,如下图所示:
对象及其存储在内存中的表面位图
Flash Player 10.1 和 AIR 2.5 优化内存使用的方法与
滤镜和动态位图卸载
中介绍的方法相同。如果隐藏缓存的显示对象或将其置于屏幕之外,则在一段时间未使用后释放其位图占用的内存。
注:
如果将显示对象的
opaqueBackground
属性设置为特定颜色,运行时会将显示对象视为不透明。当运行时与
cacheAsBitmap
属性一起使用时,它将在内存中创建一个非透明的 32 位位图。将 alpha 通道设置为 0xFF 可提高性能,因为在屏幕上绘制位图时不要求透明度。避免使用 alpha 混合可提高呈现速度。如果当前屏幕深度限制为 16 位,则内存中的位图会存储为 16 位图像。使用
opaqueBackground
属性不会隐式激活位图缓存。
要节省内存,请使用
cacheAsBitmap
属性,并对每个显示对象而不是容器激活该属性。对容器激活位图缓存会导致最终位图占用更多内存,从而创建一个尺寸为 211 x 279 像素的透明位图。此图像大约占用 229 KB 内存:
此外,通过缓存容器,如果任何苹果开始在帧上移动时,您将面临在内存中更新整个位图的风险。对各个实例激活位图缓存会导致在内存中缓存 6 个 7KB 的表面,总共仅使用 42 KB 内存:
访问显示列表中的各个苹果实例并调用
getChildAt()
方法,会将引用存储在 Vector 对象中以便于访问:
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);
}
}
}
请记住,如果不在各个帧上旋转、缩放或更改缓存的内容,则位图缓存可提高呈现效果。但是,对于 X 和 Y 轴上的平移之外的任何转换,则不会提高呈现性能。在这些情况下,每次在显示对象上发生转换时,Flash Player 都将更新缓存的位图副本。更新缓存副本会导致占用大量 CPU、降低性能以及消耗大量电池电量。同样,AIR 或 Packager for iPhone 中的
cacheAsBitmapMatrix
属性也没有此限制。
以下代码会更改移动方法中的 alpha 值,这会更改每个帧中苹果的不透明度:
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();
}
使用位图缓存会导致性能降低。更改 alpha 值会强制运行时在修改 alpha 值时更新内存中的缓存位图。
滤镜依赖每次缓存的影片剪辑的播放头移动时更新的位图。因此,使用滤镜会自动将
cacheAsBitmap
属性设置为
true
。下图演示了一个动画影片剪辑:
动画影片剪辑
请避免在动画内容中使用滤镜,因为这可能导致性能问题。在下图中,设计人员添加了一个投影滤镜:
使用投影滤镜的动画影片剪辑
因此,如果播放影片剪辑内部的时间轴,则必须重新生成位图。如果以简单的 x 或 y 转换以外的任何方式修改内容,则也必须重新生成位图。每个帧都会强制运行时重绘位图,这需要更多的 CPU 资源、导致性能非常低,并缩短电池寿命。
Paul Trani 提供了以下培训视频,演示了如何使用 Flash Professional 和 ActionScript 来优化使用位图的图形: