警告:我在这里给出的技巧对于JavaFX Mobile的当前版本是正确的,该版本是JavaFX 1.1 SDK的一部分。 在将来的版本中,行为将改变,上述工件的当前不良性能将被优化或至少得到显着改善。 我在这里写的所有内容都是快照,不应理解为

最后!

项目3:使用简单的形状代替图像
第4项:使用小图像代替复杂形状

这两个项目似乎相互矛盾。 不幸的是,这里没有简单的答案:有时使用形状更好,有时使用图像更好。 为了帮助您做出正确的决定,以下是应考虑的几点:

  • 复杂性单个基本形状(例如矩形或圆形)几乎总是比图像更快。 但是,为了获得所需的工件而组装的形状数量越多,或者用户定义的路径越复杂,对这些形状进行的操作就越昂贵。 并且优势缩小。 重要说明:javafx.text.Text对象是一个非常复杂的形状。
  • 大小大多数图像操作的性能都是二次方的,这意味着如果宽度和高度加倍,则操作的速度变为4倍,如果将宽度和高度加倍,则操作的速度变为9倍,等等。因此,元素越大,使用形状越好。
  • 变换旋转或缩放不仅在使用形状时看起来更好,而且通常也比变换图像更快。 特别是如果旋转和缩放设置为动画,则形状会更好。
  • 启动时间加载图像和设置ImageView通常比设置形状要慢。
  • 足迹静态和动态的足迹几乎总是使用较高的图像时。

重要说明:运行时当前未使用javafx.scene.Node的变量缓存。 设置它没有区别!

现在我们将专注于图像加载

项目5:使用预缩放功能
如果图像需要缩放并且缩放比例以后没有更改,建议使用预缩放功能。 这可以通过设置Image对象的宽度和高度来完成,该对象将在加载图像时缩放图像。

使用预缩放有两个好处。 首先,它可以带来更好的性能。 如果使用预缩放,则缩放肯定只计算一次。 相反,每当ImageView对象的变换被其他东西(然后是平移)更改时,都会重新计算其缩放比例。 例如,更改旋转度将导致重新计算缩放比例。 其次,如果图像按比例缩小,则使用预缩放后,内存使用量将大大减少。
如果标志Image.smooth为false,则可以更快地计算缩放比例。 但是必须检查缩放图像的质量。


本示例为许多图像生成缩略图。 代码示例1使用ImageView的缩放功能创建了一系列缩略图。

def thumbnails = for (i in [0..11])
     ImageView {
         image: Image {url: "{__DIR__}images/img{i}.png"}
         preserveRatio: true
         fitWidth: 30
         fitHeight: 20
     }

代码示例1:在ImageView中缩放
如代码示例2所示,使用Image类的预缩放功能可以实现相同的效果。使用此方法显示缩略图通常更快,并且内存使用量要小得多。

def thumbnails = for (i in [0..11])
     ImageView {
         image: Image {
             url: "{__DIR__}images/img{i}.png"
             preserveRatio: true
             width: 30
             height: 20
         }
     }

代码示例2:使用图像进行预缩放

项目6:使用后台加载
Image类提供了一个很好的但容易被忽略的功能,可以在后台异步加载图像。 这不会提高运行时性能或减少应用程序的占用空间,但可以大大缩短启动时间。 要启用它,必须设置标志Image.backgroundLoading。 后台加载有两个后果,在实现过程中需要考虑这些后果。 如果应该在创建后不久显示加载在后台的图像,则必须检查下载进度。 否则,将首先显示空白图像。 另一个选择是将变量占位符设置为显示替代图像,直到完成实际图像的加载为止。 在下面的示例中使用了这种方法。

第二个结果是,在完全加载图像之前,不会设置图像的宽度和高度。 这可能会破坏任何布局,这取决于所用图像的大小。 同样,如果占位符图像和最终图像的大小相同,则可以使用占位符图像来克服这一问题。 或者可以手动设置宽度和高度,这会将图像预缩放为给定的大小。 最后一个选项是在图像加载完成后重新计算布局。


代码示例3从上方扩展了示例,以在后台加载缩略图并显示它们。 加载图像后,将显示一个占位符(logo.png),其大小与缩略图相同。 请注意,徽标未加载到背景中,以确保我们可以立即显示它。

def logo = Image {url: "{__DIR__}images/logo.png"}

 def thumbnails = for (i in [0..11])
     ImageView {
         image: Image {
             url: "{__DIR__}images/img{i}.png"
             preserveRatio: true
             width: 30
             height: 20
             backgroundLoading: true
             placeholder: logo
         }
         x: i mod 4 * 50 + 20
         y: ((i/4) as Integer) * 40 + 20
 }

 Stage {scene: Scene {content: thumbnails}}

代码示例3:在后台加载缩略图
在仿真器上,必须看起来非常接近才能注意到后台加载。 在真实设备上,加载图像通常需要更长的时间。 启用背景加载后,屏幕将快速显示,首先仅显示占位符,这些占位符被实际图像一个接一个地替换。 如果禁用了后台加载,则该应用程序将显示空白屏幕,直到完全加载并显示所有图像为止。

第7项:使用def而不是var定义变量。 使它们成为脚本专用。
在定义实例变量时,优良作法是尽可能限制可访问性。 同样,如果变量立即被初始化且之后没有重新分配,则应使用关键字def对其进行定义。 几乎所有绑定变量都是如此,因为绑定变量无法重新分配(不存在非绑定操作),并且通常在定义它们时就已经知道它们绑定的对象。

除了产生更清晰,更不易出错的代码外,遵循这些建议还可以提高性能。 我们可以提供给编译器的提示越多,它就越可以优化我们的代码。 让我们看一下代码示例1中的示例。

class Main {
     def i1: Integer = 0;
     var i2: Integer;
     public def i3: Integer = 0;
     public var i4: Integer;
 }

代码示例1:具有公共,私有def和var的示例脚本
代码示例1定义了一个具有四个成员i1,i2,i3和i4的小类。 变量i1和i2是专用脚本,i3和i4是公共变量; 变量i1和i3用def定义,i2和i4用var定义。 代码示例2显示了部分生成的Java代码。

class Main extends java.lang.Object implements Main$Intf,com.sun.javafx.runtime.FXObject{
     public int $Main$i1;
     public int $Main$i2;
     public int $i3;
     public final com.sun.javafx.runtime.location.IntVariable $i4;
     ...
 }

代码示例2:从代码示例1生成的Java代码的一部分
生成的Java代码的显着之处在于,除i4之外的所有变量都变成了简单的整数。 只有变量i4被转换为IntVariable,因为它需要提供更多功能。 一个Int变量比IntVariable实例需要更少的内存并执行得更快。

条款8:使用整数代替数字
整数运算总是比浮点值运算快。 在通常没有台式计算机之类的数学协处理器的有限设备上,两者之间的差异是巨大的。 因此,最好在可能的情况下使用Integer。 JavaFX编译器的类型推断机制通常在确定变量的正确类型方面做得很好,但是如果有疑问,它将选择Number。 因此,应始终明确设置Integer变量的类型。

条款9:使用Sequence类的功能
软件包javafx.util中的Sequences类提供了大量用于处理序列的有用函数。 应该熟悉提供的功能并使用它们,而不要自己实现。 序列中的功能已经过全面测试,其性能至少要好于自己实现的性能。