Статьи

Лучшие практики для мобильных приложений JavaFX, часть 2

ВНИМАНИЕ: Советы, которые я даю здесь, верны для текущей версии 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.

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

Пример кода 1: масштабирование в ImageView
То же самое может быть достигнуто с помощью функции предварительного масштабирования класса Image, как показано в примере кода 2. При таком подходе отображение миниатюр обычно выполняется быстрее, а использование памяти намного меньше.

1
2
3
4
5
6
7
8
9
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), размер которого совпадает с размером миниатюр. Обратите внимание, что логотип не загружается в фоновом режиме, чтобы мы могли отображать его немедленно.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
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. Это верно почти для всех связанных переменных, потому что связанные переменные не могут быть переназначены (нет такой вещи как unbound-операция), и обычно каждый уже знает, с чем они связаны, когда они определены.

Помимо получения более четкого и менее подверженного ошибкам кода, выполнение этих рекомендаций также повышает производительность. Чем больше подсказок мы можем предоставить компилятору, тем агрессивнее он может оптимизировать наш код. Давайте посмотрим на пример в примере кода 1.

1
2
3
4
5
6
class Main {
     def i1: Integer = 0;
     var i2: Integer;
     public def i3: Integer = 0;
     public var i4: Integer;
 }

Пример кода 1: пример скрипта с публичными, приватными определениями и переменными
Пример кода 1 определяет небольшой класс с четырьмя членами i1, i2, i3 и i4. Переменные i1 и i2 являются частными для сценариев, i3 и i4 являются открытыми; переменные i1 и i3 определены с помощью def, i2 и i4 определены с помощью var. Пример кода 2 показывает часть сгенерированного кода Java.

1
2
3
4
5
6
7
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: части сгенерированного кода Java из примера кода 1
Что примечательно в сгенерированном коде Java, так это тот факт, что все переменные, кроме i4, стали простыми числами; только переменная i4 преобразуется в IntVariable, потому что она должна предоставлять больше функциональности. Переменная int требует меньше памяти и работает быстрее, чем экземпляр IntVariable.

Пункт 8: Используйте целое число вместо числа
Операции над целыми числами всегда быстрее, чем операции со значениями с плавающей точкой. На ограниченном устройстве, которое обычно не имеет математического сопроцессора, как настольные компьютеры, разница непомерна. Поэтому рекомендуется использовать целые числа всегда, когда это возможно.
Механизм вывода типов компилятора JavaFX обычно очень хорошо определяет правильный тип переменной, но в случае сомнений он выберет Number. Поэтому всегда следует явно указывать тип целочисленных переменных.

Пункт 9: Используйте функции класса Sequence
Класс Sequence в пакете javafx.util предоставляет большое количество полезных функций для работы с последовательностями. Нужно быть знакомым с предоставленными функциями и использовать их вместо того, чтобы реализовывать их самостоятельно. Функции в последовательностях были тщательно протестированы, и производительность, по крайней мере, такая же хорошая, если не лучше, чем у собственных реализаций.

Ссылка: Рекомендации для мобильных приложений JavaFX 3 и Рекомендации для мобильных приложений JavaFX 4 и Рекомендации для мобильных приложений JavaFX 5 от нашего партнера JCG