本文将讨论你能够制定的用来保持你的Flex移动应用程序运行流畅的性能决策。 你能够采取用来确保获得卓越性能的唯一最重要的步骤是使用许多与Flex 4.6一起发行的高度优化的移动组件、皮肤以及条目渲染器(item renderer)并且以它们为基础建立其它组件。 使用这些组件并遵循本文中概述的一套最佳方法,你会在使用单一Flex编码基的 iOS、Android以及QNX设备上体验到高帧速率和快速加载时间带来的乐趣。

ActionScript条目渲染器优化

一个移动应用程序可能会包括数十个条目渲染器,并且当你的应用程序的确包括这么多条目渲染器时,对它们进行优化就变得很重要。 优化条目渲染器将会使你的应用程序在滚动过程中保持高的帧速率,这将给你的用户带来流畅、响应快速的体验。 Flex团队推荐你在ActionScript中编写条目渲染器以便于获得最佳的性能。 ActionScript条目渲染器与MXML条目渲染器相比编写的难度较大,然而相应的性能增益非常显著。 尽管MXML条目渲染器能够提供许多便利,其中包括状态语法(state syntax)、动态布局(dynamic layout)以及绑定表达式(binding expressions),然而ActionScript条目渲染器为了换取速度牺牲了这些便利。

子类LabelItemRenderer/IconItemRenderer

你可以通过利用ActionScript编写你的条目渲染器并建立高度优化的Flex LabelItemRenderer或者IconItemRenderer来改进相应的性能。 为了实现你的LabelItemRenderer或者IconItemRenderer子类,你可以覆盖条目渲染器的数据setter函数和createChildrenmeasuredrawBackground以及layoutContents方法。

为了开始创建一个能够扩展LabelItemRenderer以及覆盖这些方法的ActionScript模版,请遵循下面的这些步骤:

  1. 在Flash Builder 4.6中,选中File > New > Item Renderer。
  2. 输入你的条目渲染器的名称。
  3. 选中第二个标题为Custom ActionScript Item Renderer For Mobile List (ActionScript)的模版。
  4. 单击Finish。

相应的生成代码将包括一些注解,它们用来解释在每一个被覆盖的方法中需要做些什么。 如需获得每一个被覆盖的方法的更多详细的代码范例,请务必钻研各种相应的超级类(superclass)的方法。

如果你熟悉Flex组件生命周期,那么你可能注意到一个新的惯例:updateDisplayList已被分割成两个新的方法:drawBackgroundlayoutContents。 在LabelItemRenderer和IconItemRenderer中,updateDisplayList先调用drawBackground,其次再调用layoutContents

图1显示了一个简单的显示股票行情符号以及它们值的变化的ActionScript条目渲染器的范例。

图1. StockRenderer条目渲染器

图1. StockRenderer条目渲染器

StockRenderer类能够扩展LabelItemRenderer,它使用一个自定义背景,并创建一个额外的StyleableTextField以便用于显示股票值的变化。 下面是相应的代码:

public class StockRenderer extends LabelItemRenderer { private const PADDING:Number = 20; private const GAP:Number = 40; private var change:Number; private var changeLabel:StyleableTextField; public function StockRenderer() { super(); } override public function set data(value:Object):void { super.data = value; change = (data ? data.change : 0.0); changeLabel.text = (change > 0 ? "+" : "") + change.toString(); invalidateDisplayList(); } override protected function createChildren():void { super.createChildren(); if (!changeLabel) { // Create a StyleTextField to display the stock's change value, and add it to the display list. changeLabel = StyleableTextField(createInFontContext(StyleableTextField)); changeLabel.styleName = this; changeLabel.editable = false; changeLabel.selectable = false; changeLabel.multiline = false; changeLabel.wordWrap = false; addChild(changeLabel); } } override protected function measure():void { // Determine the item renderer's desired width and height. measuredWidth = PADDING + labelDisplay.getPreferredBoundsWidth() + GAP + changeLabel.getPreferredBoundsWidth() + PADDING; measuredHeight = PADDING + Math.max(labelDisplay.getPreferredBoundsHeight(), changeLabel.getPreferredBoundsHeight()) + PADDING; measuredMinWidth = measuredWidth; measuredMinHeight = measuredHeight; } override protected function drawBackground(unscaledWidth:Number, unscaledHeight:Number):void { // Choose green or red for the background color based on the stock's change value. var backgroundColors:Array = (change >= 0 ? [0x00CC00, 0x009900] : [0xCC0000, 0x990000]); // Create a matrix to rotate the background gradient 90 degrees. var matrix:Matrix = new Matrix(); matrix.createGradientBox(unscaledWidth, unscaledHeight, Math.PI / 2, 0, 0); // Draw the gradient background. graphics.beginGradientFill(GradientType.LINEAR, backgroundColors, [1.0, 1.0], [0, 255], matrix); graphics.drawRect(0, 0, unscaledWidth, unscaledHeight); graphics.endFill(); } override protected function layoutContents(unscaledWidth:Number, unscaledHeight:Number):void { // Position labelDisplay against the left edge, and vertically align it. var labelDisplayX:Number = PADDING; var labelDisplayY:Number = (unscaledHeight - labelDisplay.getPreferredBoundsHeight()) / 2; setElementPosition(labelDisplay, labelDisplayX, labelDisplayY); // Position changeLabel against the right edge, and vertically align it. var changeLabelX:Number = unscaledWidth - changeLabel.getPreferredBoundsWidth() - PADDING; var changeLabelY:Number = (unscaledHeight - changeLabel.getPreferredBoundsHeight()) / 2; setElementPosition(changeLabel, changeLabelX, changeLabelY); } }

当在条目渲染器中显示图像时,使用子类IconItemRenderer

在内部,IconItemRenderer使用Flex ContentCache类来高速缓存外部下载的图标图像。 这意味着当用户向下滚动一个包含IconItemRenderers的列表时,从服务器加载外部的图像将会耗费一点时间,然而当用户反向向上滚动时,图像会立即出现,因为它直接来自IconItemRenderer缓存器。

使用StyleableTextField而非Label或者RichText来显示文本

StyleableTextField在渲染文本方面与Label或者RichText相比速度更快,因此在ActionScript条目渲染器中一直都是使用它来显示文本。 注意,StyleableTextField只能在ActionScript中使用,因此你不能在MXML条目渲染器或者MXML视图中使用它。

MXML条目渲染器优化

在ActionScript中编写条目渲染器将会获得最佳的性能。 但是,你仍可以使用MXML条目渲染器来获得相似的性能水平,然而你需要小心地使用下面的优化措施来调整它们。

保持你的条目渲染器的外观处于静态状态并小心使用cacheAsBitmap

cacheAsBitmap属性能够对性能产生积极或消极影响,这取决于它的使用方式。 如果一个条目渲染器的内部外观不经常改变,那么仅仅将cacheAsBitmap设置为true即可。 当条目渲染器的外观保持不变并且只有它的位置发生变化时,运行时能够快速地在它的新位置中重新绘制条目渲染器的缓存位图。 但是,条目渲染器的内部外观每发生一次改变,运行时都必须重新创建一张位图,这将会花费一些时间并对性能造成损害。

相同的情形也会发生在所有的组件上,而不仅仅只发生在条目渲染器上。 例如,千万不要在List上设置cacheAsBitmap。 在滚动时每一帧的List组件的内部外观均会改变,这将要求每一帧的运行时均重新产生许多多余的位图,从而显著降低帧速率。

如需了解更多关于cacheAsBitmap的信息,请查看Glenn Ruehle在他的47分钟的演说建立Flex Tablet应用程序的最佳方法(Best Practices for Building Flex Tablet Applications)中对正确使用cacheAsBitmap的解释。

保持你的条目渲染器的矩形形状及不透明状态并设置opaqueBackground

不像cacheAsBitmap那样,如果不当使用将容易损害性能,而opaqueBackground却只会改进性能。 但是,你的条目渲染器必须是矩形形状并且不透明以便于正确地进行渲染。

在系统内部,opaqueBackground属性能够指示运行时使用一个高度优化并且能够忽略透明度计算(transparency calculation)的渲染路径。

为了使用opaqueBackground属性,你需要在一个条目渲染器上将它设置为一个特定的颜色。 即使你为opaqueBackground设置一个单一颜色,你仍然能够使用另外一种自定义不透明的背景完全地覆盖住该颜色并且获得性能上的优势。

下面是一个简单条目渲染器,它能够设置opaqueBackground以便获得性能增益,并且在一个梯度填充(gradient-filled )的Rect的纯色背景中完美地进行绘画操作:

<s:ItemRenderer xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:s="library://ns.adobe.com/flex/spark" cacheAsBitmap="true" opaqueBackground="0xFF0000" autoDrawBackground="false"> <s:Rect left="0" right="0" top="0" bottom="0"> <s:fill> <s:LinearGradient rotation="90"> <s:GradientEntry color="#FFFFFF" ratio="0"/> <s:GradientEntry color="#DDDDDD" ratio=".33"/> <s:GradientEntry color="#999999" ratio=".66"/> </s:LinearGradient> </s:fill> </s:Rect> <s:Label id="labelDisplay" left="5" right="5" top="15" bottom="15"/> </s:ItemRenderer>

如果你绘制你自己的背景,那么你需要关闭autoDrawBackground

如果你按照之前代码范例中使用的方式在你的条目渲染器中定义一个背景Rect,那么你应该关闭autoDrawBackground。 这一操作将会指示Flex不要浪费时间来绘制一个你无论如何都会覆盖的默认背景。

使用Label而非RichText来显示文本

虽然StyleableTextField是显示文本最快速的组件,但是你仍然不能在MXML中使用它。 下一个你可以在MXML中使用的最快速组件是Label。 最为重要的是,你应该一直避免在你的应用程序中使用RichText,因为它不是用来优化移动设备的。

覆盖数据setter函数而非使用绑定表达式(binding expression)

在系统内部,绑定表达式(binding expression)能够调度事件并且运行额外的ActionScript代码。 复合绑定表达式(complex binding expression)和双向绑定表达式(two way binding expression)甚至更加冗长。 幸运的是,你可以方便地通过在一个已被覆盖的数据调 setter函数中更新条目渲染器的显示,以避免在条目渲染器中使用绑定表达式(binding expression)。

例如,你可以按照下面的方式覆盖条目渲染器的数据setter函数:

<s:ItemRenderer xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:s="library://ns.adobe.com/flex/spark" cacheAsBitmap="true" opaqueBackground="0xFF0000" autoDrawBackground="false"> <fx:Script> <![CDATA[ override public function set data(value:Object):void { super.data = value; if (data) { nameLabel.text = data.name; phoneNumberLabel.text = data.phoneNumber; } else { nameLabel.text = ""; phoneNumberLabel.text = ""; } } ]]> </fx:Script> <s:Rect id="background" left="0" right="0" top="0" bottom="0" > <s:fill> <s:LinearGradient rotation="90"> <s:GradientEntry color="#FFFFFF" ratio="0"/> <s:GradientEntry color="#DDDDDD" ratio=".33"/> <s:GradientEntry color="#999999" ratio=".66"/> </s:LinearGradient> </s:fill> </s:Rect> <s:Label id="nameLabel" left="5" right="5" top="15" bottom="15" fontSize="12"/> <s:Label id="phoneNumberLabel" left="5" right="5" top="30" bottom="15" fontSize="10"/> </s:ItemRenderer> The previous method is much faster than using binding in an item renderer like this: <?xml version="1.0" encoding="utf-8"?> <s:ItemRenderer xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:s="library://ns.adobe.com/flex/spark" cacheAsBitmap="true" opaqueBackground="0xFF0000" autoDrawBackground="false"> <s:Rect id="background" left="0" right="0" top="0" bottom="0" > <s:fill> <s:LinearGradient rotation="90"> <s:GradientEntry color="#FFFFFF" ratio="0"/> <s:GradientEntry color="#DDDDDD" ratio=".33"/> <s:GradientEntry color="#999999" ratio=".66"/> </s:LinearGradient> </s:fill> </s:Rect> <s:Label id="nameLabel" value="{data.name}" left="5" right="5" top="15" bottom="15" fontSize="12"/> <s:Label id="phoneNumberLabel" value="{data.phoneNumber}" left="5" right="5" top="30" bottom="15" fontSize="10"/> </s:ItemRenderer>

前面的方法与在条目渲染器中使用绑定的方法相比速度要快得多,如下所示:

<?xml version="1.0" encoding="utf-8"?> <s:ItemRenderer xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:s="library://ns.adobe.com/flex/spark" cacheAsBitmap="true" opaqueBackground="0xFF0000" autoDrawBackground="false"> <s:Rect id="background" left="0" right="0" top="0" bottom="0" > <s:fill> <s:LinearGradient rotation="90"> <s:GradientEntry color="#FFFFFF" ratio="0"/> <s:GradientEntry color="#DDDDDD" ratio=".33"/> <s:GradientEntry color="#999999" ratio=".66"/> </s:LinearGradient> </s:fill> </s:Rect> <s:Label id="nameLabel" value="{data.name}" left="5" right="5" top="15" bottom="15" fontSize="12"/> <s:Label id="phoneNumberLabel" value="{data.phoneNumber}" left="5" right="5" top="30" bottom="15" fontSize="10"/> </s:ItemRenderer>

当在你的条目渲染器中显示外部图像时,使用共享的ContentCache

如果你需要将外部图像下载到条目渲染器中,那么你应该不会希望每次当数据条目在视图中滚进滚出时都重新下载它们。 正如之前提到的那样,ActionScript IconItemRenderer使用一个 ContentCache来使得你的应用程序不必重新下载相应的组件。 通过声明一个静态的ContentCache实例并给它设置任一BitmapImage组件的contentLoader属性,你可以在你的MXML条目渲染器中进行相似的优化。 然后,该类型的所有条目渲染器将共享这个ContentCache实例,它将自动地加载并缓存你的图像。 这比它看起来还要简单一些,因此请参阅下面的代码范例:

<s:ItemRenderer xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:s="library://ns.adobe.com/flex/spark" cacheAsBitmap="true" opaqueBackground="0xFF0000" autoDrawBackground="false" initialize="initializeHandler(event)"> <fx:Script> <![CDATA[ import mx.events.FlexEvent; import spark.core.ContentCache; static private const iconCache:ContentCache = new ContentCache(); private function initializeHandler(event:FlexEvent):void { icon.contentLoader = iconCache; } override public function set data(value:Object):void { super.data = value; if (data) { nameLabel.text = data.name; phoneNumberLabel.text = data.phoneNumber; icon.source = data.imageUrl; } else { nameLabel.text = ""; phoneNumberLabel.text = ""; icon.source = null; } } ]]> </fx:Script> <s:Rect id="background" left="0" right="0" top="0" bottom="0" > <s:fill> <s:LinearGradient rotation="90"> <s:GradientEntry color="#FFFFFF" ratio="0"/> <s:GradientEntry color="#DDDDDD" ratio=".33"/> <s:GradientEntry color="#999999" ratio=".66"/> </s:LinearGradient> </s:fill> </s:Rect> <s:BitmapImage id="icon" top="10" left="5" width="32" height="32" /> <s:Label id="nameLabel" left="40" right="5" top="15" bottom="15" fontSize="12"/> <s:Label id="phoneNumberLabel" left="40" right="5" top="30" bottom="15" fontSize="10"/> </s:ItemRenderer>

为了定位组件,你需要使用BasicLayout或者ConstraintLayout,而非对Group容器进行嵌套。

你应该保持显示层级越浅越好。 将Group容器与VerticalLayout和HorizontalLayout的组合一起进行嵌套来创建复合布局将会产生许多不必要的布局代码。 相反,你可以考虑使用ConstraintLayout,或者通过使用诸如leftrighttop以及bottom等BasicLayout约束条件来明确地指定组件的位置。 你可能已注意到,在代码范例中,我已经明确地指定了位置,而非使用嵌套的Groups或者动态布局。

假定用下面的三种方式来对ContactRenderer(参见图2)进行布局,它是一个MXML条目渲染器,用来显示个人的姓名和电话号码。

图2. 一个单一的ContactRenderer实例

图2. 一个单一的ContactRenderer实例

如下所示,你可以使用BasicLayout对ContactRenderer进行布局:

<s:BitmapImage id="icon" top="10" left="5" width="32" height="32" /> <s:Label id="nameLabel" left="40" right="5" top="15" bottom="15" fontSize="12"/> <s:Label id="phoneNumberLabel" left="40" right="5" top="30" bottom="15" fontSize="10"/>

你还能够以下面的方式使用ConstraintLayout:

<s:layout> <s:ConstraintLayout> <s:constraintColumns> <s:ConstraintColumn id="leftPaddingColumn" width="5"/> <s:ConstraintColumn id="iconColumn" width="32"/> <s:ConstraintColumn id="middleGapColumn" width="3"/> <s:ConstraintColumn id="textColumn" width="100%"/> <s:ConstraintColumn id="rightPaddingColumn" width="5"/> </s:constraintColumns> <s:constraintRows> <s:ConstraintRow id="topPaddingRow" height="10"/> <s:ConstraintRow id="firstRow" height="16"/> <s:ConstraintRow id="secondRow" height="16"/> <s:ConstraintRow id="bottomPaddingRow" height="10"/> </s:constraintRows> </s:ConstraintLayout> </s:layout> <s:BitmapImage id="icon" left="iconColumn:0" top="firstRow:0" width="32" height="32"/> <s:Label id="nameLabel" left="textColumn:0" right="textColumn:0" top="firstRow:5" fontSize="12"/> <s:Label id="phoneNumberLabel" left="textColumn:0" right="textColumn:0" bottom="secondRow:2" fontSize="10"/>

如下所示,最好通过嵌套Group组件来避免定位相应的元素:

<s:Group> <s:layout> <s:HorizontalLayout paddingLeft="5" paddingTop="10" paddingBottom="10" gap="3"/> </s:layout> <s:BitmapImage id="icon" width="32" height="32" /> <s:Group> <s:layout> <s:VerticalLayout gap="3" paddingTop="5" paddingBottom="5"/> </s:layout> <s:Label id="nameLabel" fontSize="12"/> <s:Label id="phoneNumberLabel" fontSize="10"/> </s:Group>

使用Group和FXG Graphics取代BorderContainer

BorderContainer是一个用来绘制具有边界和背景的容器的适宜组件,然而它并不适用于移动设备。 取而代之的是,你应该使用包含一个Rect的Group来获得相同的视觉效果。

如下所示,使用一个包含一个Rect的Group:

<s:Group width="200" height="200"> <s:Rect left="0" right="0" top="0" bottom="0"> <s:fill> <s:SolidColor color="#CCCCCC"/> </s:fill> <s:stroke> <s:SolidColorStroke color="#999999"/> </s:stroke> </s:Rect> <!-- Define child components here --> </s:Group>

如下所示,避免使用 BorderContainer:


<s:BorderContainer width="200" height="200" backgroundColor="#CCCCCC" borderColor="#999999"> <!-- Define child components here --> </s:BorderContainer>

视图优化

移动视图应该利用MXML编写。 不像条目渲染器那样,通常在某一时刻只有一个视图可见,因此,MXML的轻松使用要胜于ActionScript的性能优势。 无论如何,当你在不同的视图间进行切换时,你需要许多优化措施来确保你的应用程序运行顺畅并且响应快速。

覆盖数据setter函数,而非在creationComplete处理程序中使用绑定或者初始化View的外观

不要在creationComplete处理程序中初始化View的外观,因为这将会导致该视图再处理,这将推迟相应的视图转换。 取而代之的是,你需要在已被覆盖的数据setter函数中改变你的视图外观。 与使用条目渲染器的情形一样,覆盖相应的数据setter函数能够消除多余的绑定表达式(binding expression)。

在viewActivate中启动异步操作并在viewDeactivate中取消它们

服务器调用等异步操作可以在视图转换过程中返回,并且需要额外的运行代码,这可能会导致视图转换产生停顿现象。 最好在视图被转换到屏幕上之后,在viewActivate处理程序中启动异步操作。 你还应该考虑一下在切换视图前清除viewDeactivate处理程序中的一些未完成的异步调用。

有条不紊地初始化子组件

在开始进行视图转换之前,Flex需要创建并布局视图的所有子视图。 在开始阶段你应该尽可能保持视图的轻量级状态,以便最大程度地降低用户互动和视图转换开始时刻之间的延时。 如果可能,你应该在视图被转换到屏幕上之后逐渐地创建组件,但这一操作应该在viewActivate事件之后进行。 你必须避免创建在初始状态的视图中不可见的组件。

使用includeIn或者excludeFrom替代可见属性以便隐藏子组件

如果可能,使用includeInexcludeFrom将不应该可见的组件从显示列表中删除。 这样能够避免对它们进行处理。 相反,如果你将 visible设置为false,那么组件将保留在显示列表上,这样需要执行不必要的布局操作和渲染过程。

为了在内存中保留视图,需要将destructionPolicy设置为"never"

如果用户经常切换回视图模式,那么你可能希望通过在内存中保留它以避免再一次创建它产生的成本。 但是,请记住在移动设备上,内存是稀缺的资源! 如果你放松对设备的RAM的限制,那么在内存中保留各种复杂的视图(或甚至保留太多简单的视图)将会降低其性能。

如下所示,为了通过使用更多内存来改善处理时间,你可以在View上将destructionPolicy设置为"never"

<s:View xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:s="library://ns.adobe.com/flex/spark" title="My View" destructionPolicy="never"> <!-- define child components here --> </s:View>

通用图形优化

下面的优化措施会帮助你在你的应用程序中加速处理各种类型的图形,而不管这些图形是由条目渲染器、视图或者其它组件显示的。

创建图像的多个备份而非缩放它或者使用位图平滑处理技术(bitmap smoothing)

使用平滑处理技术来缩放图像看起来很好,然而这却要求提供很强的处理能力。 你应该以不同的尺寸创建多个版本的图像组件,而不是创建一个大的图像组件,然后将它根据不同的屏幕分辨率和DPI级别进行缩小。 查看Flex计算机科学家Jason San Jose的文章Flex移动皮肤—第二部分:处理不同的像素密度( Flex Mobile Skins – Part 2: Handling Different Pixel Densities),以便于了解提供各种最佳方法的详细教程。

使用预焙组件(prebaked asset)、文本加倍(text doubling)或RectangularDropShadow,而非过滤器

像大多数高质量的图像处理运算那样,Spark过滤器在移动设备上的计算量过于冗长,因此你应该避免使用它们,而选择其它技术。 在大多数情形下,你可以直接在你的图像组件中绘制一个阴影。 当处理文本时,你可以复制该文本并对它进行偏移以便创建一个阴影效果。 如果你希望获得一个落在矩形组件上的阴影,那么Flex能够为 DropShadowFilter提供一个名称为RectangularDropShadow的非常有效的替代品。 RectangularDropShadow不是过滤器,而是组件,你可以基本上像使用Rect一样使用它。

如下所示,使用RectangularDropShadow:

<s:Group width="200" height="200"> <!-- drop shadow --> <s:RectangularDropShadow left="0" right="0" top="0" bottom="0" distance="3" alpha="0.5"/> <!-- background and border --> <s:Rect left="0" right="0" top="0" bottom="0"> <s:fill> <s:SolidColor color="#DDDDDD"/> </s:fill> <s:stroke> <s:SolidColorStroke color="#999999"/> </s:stroke> </s:Rect> <!-- define child components here --> </s:Group>

如下所示,避免使用DropShadowFilter:

<s:Group width="200" height="200"> <!—- drop shadow --> <s:filters> <s:DropShadowFilter distance="3" alpha="0.5"/> </s:filters> <!-- background and border --> <s:Rect left="0" right="0" top="0" bottom="0"> <s:fill> <s:SolidColor color="#DDDDDD"/> </s:fill> <s:stroke> <s:SolidColorStroke color="#999999"/> </s:stroke> </s:Rect> <!-- define child components here --> </s:Group>

使用BitmapImage而非Image进行图像嵌入操作

BitmapImage组件是一个轻量级版本的Image组件。 这两个组件都能够显示嵌入式的图像组件。 两者之间最大的差异是Image 能够即装即用加载外部图像,而BitmapImage需要一些设置才能加载外部图像。

与BitmapImage不同,Image的皮肤也是可换的并且支持丢失图像指示器。 对于嵌入图像,你不需要所有这些额外的功能,恰恰相反,你应该使用轻量级的BitmapImage组件。

如下所示,使用BitmapImage组件:

<s:BitmapImage source="@Embed('assets/icon.jpg')"/>

如下所示,避免使用Image组件:

<s:Image source="@Embed('assets/icon.jpg')"/>

使用PNGs,而非GIFs和JPEGs

运行时在对PNG文件格式进行解码时速度要快得多,因此无论在什么情况下,只要你有选择权,那么你都应该使用PNG来代替GIF和JPEG图像。

使用FXG文件绘制非平凡矢量图形(nontrivial vector graphic)

为方便起见,你应该使用MXML原语来绘制背景矩形等简单的矢量图像。 但是,对于更复杂的图形和矢量插图来说,你应该在Adobe Illustrator中或者相似的设计工具中创建FXG文件。 FXG文件由一个预编译的绘图指令序列组成,与大量在MXML中声明的原语来相比,FXG文件具有更快的执行速度并占用较少的内存。 如需了解更多关于 FXG与MXML图形对比的信息,请查看相应的FXG和MXML Graphics参考文章。

减少同步运行的效果数量

Flex能够提供Resize或Fade等效果,它们能够方便地为用户界面在响应触摸互动操作时提供动画效果。 最好应该限制一下在同一时刻运行的效果数量,这是因为就处理成本而言,它们会叠加在一起。

尽可能使用CSS样式,而非对组件重新植皮

通过使用CSS样式,你可以充分利用高度优化的默认Flex移动皮肤。 在大多数情形下,完全可以使用样式来定制你的UI组件的外观。 如需获取一些CSS样式的范例,请查看Holly Schinsky的文章设计你的Flex 4.5移动应用程序标签和工具栏的式样(Styling your Flex 4.5 Mobile Application Tabs and ActionBar)。

在创建自定义皮肤时,利用ActionScript扩展默认移动皮肤

如果CSS样式的数量不足,那么你可能会决定为某个组件编写一个自定义的移动皮肤。 你应该利用ActionScript 编写该皮肤并扩展相应的默认Flex移动皮肤以便充分利用它们的潜在的性能优化优势。 查看Jason San Jose关于移动植皮的系列文章,它们能够指导你了解相应的过程。

Flex移动性能检查列表相关推荐

  1. python检查列表是否为空_Python 中判断列表是否为空的方法

    在判断列表是否为空时,你更喜欢哪种方式?决定因素是什么? 在 Python 中有很多检查列表是否是空的方式,在讨论解决方案前,先说一下不同方法涉及到的不同因素. 我们可以把判断表达式可以分为两个阵营: ...

  2. C语言检查列表是否是回文的算法(附完整源码)

    C语言检查列表是否是回文的算法 C语言检查列表是否是回文的算法完整源码(定义,实现,main函数测试) C语言检查列表是否是回文的算法完整源码(定义,实现,main函数测试) #include < ...

  3. PHP环境安全性能检查

    PHP环境安全性能检查 PHP在Linux环境下安全配置是一个复杂的过程,其中涉及到很多的细节设置,在这里发出来一个脚本,通过这个脚本来检测你的PHP环境是否存在安全隐患,从而针对这些对你的PHP环境 ...

  4. 检查列表中的所有元素在Python中是否相同

    Here, we are implementing a python program to check whether all elements of a list are the same or n ...

  5. 游戏服务器为空请检查列表文件,游戏服务器为空请检查列表文件

    游戏服务器为空请检查列表文件 内容精选 换一换 如果请求因错误导致未被处理,则会返回一条错误响应.错误响应中包括错误码和具体错误描述.表1列出了错误响应中的常见错误码. 为了对源端服务器进行迁移可行性 ...

  6. linux的安全性能,技术|Linux 系统安全性能检查小记

    Linux系统安全性能检查小记: 1.Accounts检查 # less /etc/passwd # grep :0: /etc/passwd 注意新的用户,和UID,GID是0的用户. 2.Log检 ...

  7. HP PSC 系列一体机性能比较列表

    PSC 系列一体机性能比较列表<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" ...

  8. SM59 RFC 目标 SAP_PROXY_ESR 设置到服务资源库连接的检查列表

    设置到服务资源库连接的检查列表 1. 企业服务资源库的地址必须在 SAP 系统中已知 检查报表 SPROX_CHECK_IFR_ADDRESS. 2. 要连接到企业服务资源库,必须维护 RFC 目标 ...

  9. 游戏服务器为空请检查列表,游戏服务器为空请检查列表文件

    游戏服务器为空请检查列表文件 内容精选 换一换 如果请求因错误导致未被处理,则会返回一条错误响应.错误响应中包括错误码和具体错误描述.表1列出了错误响应中的常见错误码. 本接口用于制作私有镜像,支持: ...

最新文章

  1. 用RPM包安装MySQL的默认安装路径问题
  2. Oracle中创建、修改、删除序列
  3. Matrix Equation
  4. [css] box-sizing常用的属性有哪些?分别有什么作用?
  5. R12 应付款模块(AP):预付款(prepayment)的标准处理流程
  6. 【每日SQL打卡】​​​​​​​​​​​​​​​DAY 26丨广告效果【难度简单】​
  7. VUE 的使用,学会这些就足够了!| 原力计划
  8. msvcr80.dll 问题
  9. 达内android 代码,【达内唯一总部】Android实现获取系统应用列表-达内Android分享...
  10. 从零开始入门单片机(一):必会背景知识总结
  11. php 模块不存在,模块不存在:index.php?
  12. Labelling tools 的环境配置
  13. H5外部浏览器唤起微信分享
  14. 真 · 前端Vue实战:头条新闻开发项目(下)
  15. linux下tomcat的访问权限,关于Linux权限引起的Tomcat项目404问题
  16. 基于Pyramid Vision Transformer(PVT-v2)实现奥特曼识别
  17. Windows下安装Ubuntu16.04 及 Ubuntu常用软件配置 完全版 ~吐血整理!
  18. vue3 子组件上绑定(v-model=“xx“) 父组件传过来的值后报错
  19. Columbia Biosciences 山羊抗美洲驼 IgG:SureLight APC
  20. 云计算、大数据、人工智能本质的区别和关系

热门文章

  1. tsql_TSQL的历史
  2. t-sql 使用正则表达式_如何在T-SQL查询中使用可扩展表达式; 性能优势和实例
  3. azure 入门_Azure Cosmos DB中的子文档入门
  4. 运行中SQL Server查询存储
  5. sql计数_SQL计数区分功能概述
  6. [补档]noip2019集训测试赛(八)
  7. unity 显示、隐藏Android导航栏
  8. tensorflow神奇问题
  9. excel怎么并排查看两个工作表
  10. Day_2_Python_str_list_dict的使用