Уменьшение загрузки ЦП

Другим важным направлением оптимизации является загрузка центрального процессора. Оптимизация загрузки ЦП влияет на общую производительность, а следовательно, и на время работы мобильного устройства от аккумулятора.

Усовершенствованные возможности Flash Player 10.1 для использования ресурсов ЦП

В проигрывателе Flash Player 10.1 представлены две новые функции, позволяющие уменьшить загрузку центрального процессора. Эти функции позволяют приостанавливать и возобновлять воспроизведение SWF-содержимого, когда оно становится закадровым, и ограничивают число экземпляров Flash Player на странице.

Пауза, снижение скорости и возобновление

Примечание. Функция паузы, снижения скорости и возобновления не применяется к приложениям Adobe® AIR®.

Чтобы оптимизировать использование ресурсов ЦП и аккумулятора, в проигрыватель Flash Player 10.1 добавлена новая функция, предназначенная для работы с неактивными экземплярами. Она позволяет снизить нагрузку на ЦП за счет того, что когда содержимое появляется или исчезает с экрана, воспроизведение SWF-файла соответственно приостанавливается и возобновляется. Благодаря этой функции проигрыватель Flash Player освобождает всю возможную память путем удаления всех объектов, которые могут быть повторно созданы при возобновлении воспроизведения содержимого. Содержимое считается закадровым, если все содержимое находится за пределами экрана.

SWF-содержимое может стать закадровым в двух случаях:

  • Во время прокрутки страницы пользователем SWF-содержимое перемещается за пределы экрана.

    В этом случае любое воспроизведение видео или аудио продолжает выполняться, но визуализация останавливается. Если аудио или видео не воспроизводится, чтобы воспроизведение или выполнение кода ActionScript не приостанавливалось, задайте для HTML-параметра hasPriority значение true. Однако помните, что визуализация SWF-содержимого приостанавливается, если содержимое является закадровым или скрытым вне зависимости от значения HTML-параметра hasPriority .

  • При открытии вкладки в браузере SWF-содержимое перемещается на задний план.

    В этом случае независимо от значения тега HTML hasPriority скорость воспроизведения SWF-содержимого снижается до 2–8 кадров в секунду. Воспроизведение аудио и видео останавливается и визуализация содержимого не обрабатывается, пока SWF-содержимое снова не станет видимым.

В проигрывателе Flash Player 11.2 и более поздних версий, выполняющемся в браузерах на настольных компьютерах Windows и Mac, в приложении можно использовать событие ThrottleEvent. Flash Player отправляет событие ThrottleEvent в случае паузы, снижения скорости или возобновления воспроизведения.

Событие ThrottleEvent — это многоадресное событие, которое отправляется всеми объектами EventDispatcher, для которых зарегистрированы прослушиватели данного события. Дополнительные сведения о многоадресных событиях см. в описании класса DisplayObject .

Управление экземплярами

Примечание. Функция управления экземплярами не применяется к приложениям Adobe® AIR®.
Используйте параметр HTML hasPriority , чтобы отложить загрузку закадровых SWF-файлов.

Во Flash Player 10.1 появился новый параметр HTML — hasPriority .

<param name="hasPriority" value="true" />

Эта функция ограничивает количество экземпляров Flash Player, запускаемых на странице. Это экономит ресурсы ЦП и аккумулятора. Целью является назначение определенного приоритета SWF-содержимому, благодаря чему одно содержимое становится более важным по сравнению с другим содержимым на странице. Рассмотрим простой пример: пользователь просматривает веб-сайт, а на странице указателей размещены три различных SWF-файла. Один из них является видимым, другой — частично видимым на экране, а последний — закадровым, требующим прокрутки. Первые две анимации запускаются в обычном режиме, а запуск последней анимации откладывается, пока она не станет видимой. Этот сценарий представляет поведение по умолчанию, когда параметр hasPriority отсутствует или имеет значение false . Для обеспечения запуска SWF-файла, даже если он находится за пределами экрана, задайте для параметра hasPriority значение true . Однако вне зависимости от значения параметра hasPriority визуализация SWF-файла, который невидим для пользователя, всегда приостанавливается.

Примечание. Если доступных ресурсов ЦП недостаточно, новые экземпляры Flash Player не запускаются автоматически, даже если для параметра hasPriority задано значение true . Если новые экземпляры создаются с использованием JavaScript после загрузки страницы, эти экземпляры будут игнорировать флаг hasPriority . Любое содержимое размером 1x1 или 0x0 пикселов запускается, предотвращая отложенный запуск SWF-файлов помощника, если веб-мастер не включил флаг hasPriority . Однако SWF-файлы будут по-прежнему воспроизводиться по щелчку мыши. Это поведение называется «воспроизведением по щелчку» (click to play).

На схемах ниже показано, как работает параметр hasPriority с разными значениями.

Полноразмерное изображение
Результат использования разных значений параметра hasPriority

Полноразмерное изображение
Результат использования разных значений параметра hasPriority

Спящий режим

В проигрывателях Flash Player 10.1 и AIR 2.5 представлена новая функция для мобильных устройств, позволяющая уменьшить загрузку ЦП и, как результат, продлить срок службы аккумулятора. Эта функция работает вместе с подсветкой, предусмотренной во многих мобильных устройствах. Например, если мобильное приложение запущено и пользователь больше не использует устройство, среда выполнения обнаруживает, когда подсветка переходит в спящий режим. Затем он сбрасывает частоту кадров до 4 кадров в секунду и приостанавливает визуализацию. Для приложений AIR переход в спящий режим выполняется, когда приложение перемещается на задний план.

Код ActionScript продолжает выполняться в спящем режиме, как если бы свойству Stage.frameRate было присвоено значение 4 кадра в секунду. Но этап визуализации пропускается, поэтому пользователь не видит того, что проигрыватель работает с частотой 4 кадра в секунду. Частота кадров, равная 4 кадрам в секунду, была выбрана вместо нуля, поскольку она позволяет сохранять открытыми все соединения (NetStream, Socket и NetConnection). При установке значения, равного нулю, будут разорваны все открытые соединения. Частота обновления, равная 250 мс (4 кадра в секунду) была выбрана, поскольку многие производители устройств используют эту частоту в качестве частоты обновления. Использование этого значения позволяет поддерживать частоту кадров среды выполнения примерно на том же уровне, что и частота кадров самого телефона.

Примечание. Когда среда выполнения работает в спящем режиме, свойство Stage.frameRate возвращает частоту кадров исходного SWF-файла, а не 4 к/с.

Когда подсветка снова переводится в активный режим, визуализация возобновляется. Для частоты кадров восстанавливается исходное значение. Рассмотрим приложение мультимедийного проигрывателя, в котором пользователь воспроизводит музыку. Если экран переходит в спящий режим, среда выполнения реагирует в зависимости от типа воспроизводимого содержимого. Далее приводится список ситуаций, а также описано соответствующее поведение среды выполнения.

  • Подсветка переходит в спящий режим, воспроизводится содержимое, отличное от A/V. Визуализация приостанавливается, устанавливается частота 4 кадра в секунду.

  • Подсветка переходит в спящий режим, воспроизводится содержимое A/V. Среда выполнения принудительно включает подсветку, обеспечивая непрерывное воспроизведение.

  • Подсветка переходит из спящего режима в активный режим. Среда выполнения задает для таймера исходный параметр таймера SWF-файла и возобновляет визуализацию.

  • Проигрыватель Flash Player приостанавливает работу при воспроизведении содержимого A/V. Проигрыватель Flash Player восстанавливает для состояния подсветки системное поведение по умолчанию, поскольку содержимое A/V больше не воспроизводится.

  • Мобильное устройство получает вызов при воспроизведении содержимого A/V. Визуализация приостанавливается, устанавливается частота 4 кадра в секунду.

  • Спящий режим подсветки отключен в мобильном устройстве. Среда выполнения работает в обычном режиме.

Когда для подсветки включается спящий режим, визуализация приостанавливается и частота кадров уменьшается. Эта функция позволяет снизить загрузку ЦП, но на нее нельзя полагаться при создании действительной паузы, например в игровом приложении.

Примечание. Когда среда выполнения переходит в спящий режим или выходит из него, события ActionScript не отправляются.

Замораживание и размораживание объектов

Замораживать и размораживать объекты можно с помощью событий REMOVED_FROM_STAGE и ADDED_TO_STAGE .

Для оптимизации кода всегда замораживайте и размораживайте объекты. Замораживание и размораживание особенно важны для экранных объектов. Даже если экранные объекты больше не включены в список отображения и ожидают удаления при сборке мусора, они по-прежнему могут использовать код, влияющий на загрузку ЦП. Например, они по-прежнему могут использовать событие Event.ENTER_FRAME. Таким образом, очень важно правильно замораживать и размораживать объекты. Для этого используйте события Event.REMOVED_FROM_STAGE и Event.ADDED_TO_STAGE . Ниже показан код фрагмента ролика, проигрываемого в рабочей области, с функциями управления с клавиатуры.

// Listen to keyboard events 
stage.addEventListener(KeyboardEvent.KEY_DOWN, keyIsDown); 
stage.addEventListener(KeyboardEvent.KEY_UP, keyIsUp); 
  
// Create object to store key states 
var keys:Dictionary = new Dictionary(true); 
  
function keyIsDown(e:KeyboardEvent):void 
{ 
    // Remember that the key was pressed 
    keys[e.keyCode] = true;     
  
    if (e.keyCode==Keyboard.LEFT || e.keyCode==Keyboard.RIGHT) 
    { 
        runningBoy.play(); 
    } 
} 
  
function keyIsUp(e:KeyboardEvent):void 
{ 
    // Remember that the key was released 
    keys[e.keyCode] = false; 
  
    for each (var value:Boolean in keys) 
          if ( value ) return; 
    runningBoy.stop(); 
} 
  
runningBoy.addEventListener(Event.ENTER_FRAME, handleMovement); 
runningBoy.stop(); 
  
var currentState:Number = runningBoy.scaleX; 
var speed:Number = 15; 
  
function handleMovement(e:Event):void 
{ 
    if (keys[Keyboard.RIGHT]) 
    { 
        e.currentTarget.x += speed; 
        e.currentTarget.scaleX = currentState;     
    } else if (keys[Keyboard.LEFT]) 
    { 
        e.currentTarget.x -= speed; 
        e.currentTarget.scaleX = -currentState; 
    } 
}

Полноразмерное изображение
Фрагмент ролика, который взаимодействует с клавиатурой

При нажатии кнопки «Удалить» фрагмент ролика удаляется из списка отображения.

// Show or remove running boy 
showBtn.addEventListener (MouseEvent.CLICK,showIt); 
removeBtn.addEventListener (MouseEvent.CLICK,removeIt); 
 
function showIt (e:MouseEvent):void 
{ 
    addChild (runningBoy); 
} 
 
function removeIt(e:MouseEvent):void 
{ 
    if (contains(runningBoy)) removeChild(runningBoy); 
}

Даже после удаления из списка отображения фрагмент ролика по-прежнему отправляет событие Event.ENTER_FRAME . Фрагмент ролика все еще выполняется, но не визуализируется. В этой ситуации необходимо прослушивать соответствующие события и удалять прослушиватели, чтобы код, повышающий нагрузку на ЦП, уже не выполнялся.

// Listen to Event.ADDED_TO_STAGE and Event.REMOVED_FROM_STAGE 
runningBoy.addEventListener(Event.ADDED_TO_STAGE,activate); 
runningBoy.addEventListener(Event.REMOVED_FROM_STAGE,deactivate); 
 
function activate(e:Event):void 
{ 
    // Restart everything 
    e.currentTarget.addEventListener(Event.ENTER_FRAME,handleMovement); 
} 
 
function deactivate(e:Event):void 
{ 
    // Freeze the running boy - consumes fewer CPU resources when not shown 
    e.currentTarget.removeEventListener(Event.ENTER_FRAME,handleMovement); 
    e.currentTarget.stop(); 
}

При нажатии на кнопку «Показать» воспроизведение возобновляется, снова прослушиваются события Event.ENTER_FRAME , а управление роликом с клавиатуры работает корректно.

Примечание. Если экранный объект удаляется из списка отображения, задание для соответствующей ссылки значения null после его удаления не обеспечивает замораживание объекта. Если сборщик мусора не запускается, объект продолжает использовать ресурсы памяти и ЦП, даже если объект больше не отображается. Чтобы объект использовал минимум ресурсов ЦП, убедитесь, что он полностью заморожен при удалении из списка отображения.

Начиная с версий Flash Player 10 и AIR 1.5 реализовано следующее поведение. Если точка воспроизведения обнаруживает пустой кадр, экранный объект замораживается автоматически, даже если разработчик не реализовал поведение замораживания.

Принцип замораживания также важен при загрузке удаленного содержимого с использованием класса Loader. При использовании класса Loader в проигрывателе Flash Player 9 и AIR 1.0 нужно было вручную размораживать содержимое путем прослушивания события Event.UNLOAD , отправленного объектом LoaderInfo. Каждый объект нужно было размораживать вручную, что являлось нетривиальной задачей. В проигрывателях Flash Player 10 и AIR 1.5 в классе Loader представлен новый важный метод unloadAndStop() . Этот метод позволяет выгрузить SWF-файл, автоматически разморозить каждый объект в загруженном SWF-файле и принудительно запустить выполнение сборки мусора.

В следующем коде SWF-файл загружается, а затем выгружается с использованием метода unload() , что требует дополнительной обработки и замораживания вручную.

var loader:Loader = new Loader(); 
 
loader.load ( new URLRequest ( "content.swf" ) ); 
 
addChild ( loader ); 
 
stage.addEventListener ( MouseEvent.CLICK, unloadSWF ); 
 
function unloadSWF ( e:MouseEvent ):void 
{ 
    // Unload the SWF file with no automatic object deactivation 
    // All deactivation must be processed manually 
    loader.unload(); 
}

Наилучшим приемом является использование метода unloadAndStop() , в котором предусмотрены внутренняя обработка замораживания и принудительное включение процесса сборки мусора.

var loader:Loader = new Loader(); 
 
loader.load ( new URLRequest ( "content.swf" ) ); 
 
addChild ( loader ); 
 
stage.addEventListener ( MouseEvent.CLICK, unloadSWF ); 
 
function unloadSWF ( e:MouseEvent ):void 
{ 
    // Unload the SWF file with automatic object deactivation 
    // All deactivation is handled automatically 
    loader.unloadAndStop(); 
}

При вызове метода unloadAndStop() выполняются следующие действия.

  • Останавливается воспроизведение звука.

  • Прослушиватели, зарегистрированные для основной временной шкалы SWF-файла, удаляются.

  • Объекты таймера останавливаются.

  • Аппаратные периферийные устройства (например, камера и микрофон) освобождаются.

  • Каждый фрагмент ролика останавливается.

  • Отправка событий Event.ENTER_FRAME , Event.FRAME_CONSTRUCTED , Event.EXIT_FRAME , Event.ACTIVATE и Event.DEACTIVATE останавливается.

Активация и отключение событий

Определять бездействие при перемещении на задний план и оптимизировать работу приложения соответствующим образом можно с помощью событий Event.ACTIVATE и Event.DEACTIVATE .

Два события ( Event.ACTIVATE и Event.DEACTIVATE ) помогут настроить приложение таким образом, чтобы для него требовалось как можно меньше ресурсов ЦП. Эти события позволяют обнаружить, когда среда выполнения получает или теряет фокус. Таким образом, код можно оптимизировать в соответствии с изменениями контекста. Следующий код прослушивает оба события и динамически изменяет частоту кадров до нуля, когда приложение теряет фокус. Например, приложение может потерять фокус, если пользователь переключится на другую вкладку или переместит приложение на задний план.

var originalFrameRate:uint = stage.frameRate; 
var standbyFrameRate:uint = 0; 
  
stage.addEventListener ( Event.ACTIVATE, onActivate ); 
stage.addEventListener ( Event.DEACTIVATE, onDeactivate ); 
  
function onActivate ( e:Event ):void 
{ 
    // restore original frame rate 
    stage.frameRate = originalFrameRate; 
} 
  
function onDeactivate ( e:Event ):void 
{ 
    // set frame rate to 0 
    stage.frameRate = standbyFrameRate; 
}

Когда приложение вновь получает фокус, восстанавливается исходное значение частоты кадров. Вместо значительного изменения частоты кадров можно применить другие способы оптимизации, например замораживание и размораживание объектов.

С помощью активации и отключения событий можно реализовать аналогичный механизм для функции паузы и возобновления, которая иногда встречается на мобильных устройствах и нетбуках.

Взаимодействие с мышью

По возможности отключайте функции взаимодействия с мышью.

При работе с интерактивным объектом, таким как фрагмент ролика или спрайт, среда выполнения исполняет собственный код для обнаружения и обработки взаимодействия с мышью. Если на экране много интерактивных объектов, тем более если они наложены друг на друга, обнаружение взаимодействия с мышью требует значительных ресурсов ЦП. Чтобы избежать ненужной обработки, отключите взаимодействие с мышью объектов, которым оно не требуется. Ниже показано использование в коде свойств mouseEnabled и mouseChildren .

// Disable any mouse interaction with this InteractiveObject 
myInteractiveObject.mouseEnabled = false; 
const MAX_NUM:int = 10; 
  
// Create a container for the InteractiveObjects 
var container:Sprite = new Sprite(); 
  
for ( var i:int = 0; i< MAX_NUM; i++ ) 
{ 
    // Add InteractiveObject to the container 
    container.addChild( new Sprite() ); 
} 
  
// Disable any mouse interaction on all the children 
container.mouseChildren = false;

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

Сравнение таймеров с событиями ENTER_FRAME

Выберите таймеры или события ENTER_FRAME — в зависимости от наличия анимации.

Для неанимированного содержимого, выполняемого в течение длительного времени, таймеры предпочтительнее событий Event.ENTER_FRAME .

В ActionScript 3.0 предусмотрено два способа вызова функции через определенные интервалы. Первый — с помощью события Event.ENTER_FRAME , отправляемого экранными объектами (DisplayObject). Второй — с помощью таймера. Разработчики ActionScript часто используют первый способ (событие ENTER_FRAME ). Событие ENTER_FRAME отправляется в каждом кадре, поэтому интервал вызова функции зависит от текущей частоты кадров. Частота кадров задается свойством Stage.frameRate . Однако в ряде случаев лучше использовать таймер, чем событие ENTER_FRAME . Например, если у вас нет анимации, но вам требуется, чтобы код вызывался через заданные интервалы, следует использовать таймер.

Таймер действует подобно событию ENTER_FRAME , однако событие может отправляться без привязки к частоте кадров. Такое поведение дает простор для оптимизации. Рассмотрим в качестве примера проигрыватель видео. В этом случае высокая частота кадров не нужна, так как движение контролируется только приложением.

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

В этом примере частота кадров составляет 10 к/с. Таймер обновляет элементы управления с частотой раз в секунду. Метод updateAfterEvent() объекта TimerEvent позволяет повысить частоту обновления. Этот метод вызывает обновление экрана при каждой отправке события. Это проиллюстрировано в следующем коде.

// Use a low frame rate for the application 
stage.frameRate = 10; 
  
// Choose one update per second 
var updateInterval:int = 1000; 
var myTimer:Timer = new Timer(updateInterval,0); 
  
myTimer.start(); 
myTimer.addEventListener( TimerEvent.TIMER, updateControls ); 
  
function updateControls( e:TimerEvent ):void 
{ 
    // Update controls here 
    // Force the controls to be updated on screen 
    e.updateAfterEvent(); 
}

Вызов метода updateAfterEvent() не изменяет частоту кадров. Он просто заставляет среду выполнения обновлять на экране измененное содержимое. Временная шкала по-прежнему обновляется с частотой 10 к/с. Имейте в виду, что точность таймеров и событий ENTER_FRAME может снижаться при выполнении на низкопроизводительных устройствах или в случаях, когда функции обработчика событий содержат код, требующий интенсивной обработки. Как и частота кадров SWF-файла, частота обновления кадров таймера может зависеть от ряда факторов.

Сократите до минимума количество объектов Timer и зарегистрированных обработчиков события enterFrame в приложении.

Каждый кадр среды выполнения отправляет событие enterFrame всем экранным объектам из списка отображения. Можно зарегистрировать прослушиватели события enterFrame и для нескольких экранных объектов, однако это приведет к увеличению объема кода, выполняемого в каждом кадре. Вместо этого используйте единый централизованный обработчик enterFrame для выполнения всего объема кода в каждом кадре. Централизация кода облегчит управление часто выполняемым кодом.

Аналогичным образом обстоит ситуация и с объектами Timer. Создание и отправка событий множеством объектов Timer сильно нагружают код. Если необходимо запустить различные операции с различными интервалами, ниже приводятся некоторые рекомендуемые альтернативные варианты:

  • Сократите до минимума количество объектов Timer и групповых операций в зависимости от частоты их выполнения.

    Например, используйте экземпляр Timer для частых операций, которые необходимо выполнять каждые 100 миллисекунд. Затем используйте еще один экземпляр Timer для частых операций, которые необходимо выполнять менее часто, каждые 2000 миллисекунд.

  • Используйте единственный объект Timer, в котором период выполнения различных операций задан в свойстве delay .

    К примеру, необходимо, чтобы одни операции выполнялись каждые 100 миллисекунд, а другие — каждые 200 миллисекунд. В этом случае используйте один объект Timer, свойство delay которого настроено на 100 миллисекунд. В обработчике событий timer добавьте условную конструкцию, после чего каждая вторая операция будет выполняться с интервалом 200 миллисекунд. Следующий пример иллюстрирует такой подход:

    var timer:Timer = new Timer(100); 
    timer.addEventListener(TimerEvent.Timer, timerHandler); 
    timer.start(); 
         
    var offCycle:Boolean = true; 
      
    function timerHandler(event:TimerEvent):void 
    { 
        // Do things that happen every 100 ms 
         
        if (!offCycle) 
        { 
            // Do things that happen every 200 ms 
        } 
         
        offCycle = !offCycle; 
    }
Останавливайте неиспользуемые объекты Timer.

Если обработчик события timer объекта Timer выполняет операции только при определенных условиях, вызовите метод stop() объекта Timer, если ни одно из условий не принимает значение true.

В событии enterFrame или обработчиках Timer уменьшите число изменений внешнего вида экранных объектов, чтобы экран обновлялся как можно реже.

В каждом кадре в фазе визуализации производится перерисовка изменившихся элементов рабочей области. Если область перерисовки большая, или если область перерисовки небольшая, но содержит множество сложных экранных объектов, среде выполнения требуется больше времени для визуализации. Чтобы узнать объем перерисовки, воспользуйтесь функцией «Показать область перерисовки» в отладчике проигрывателя Flash Player или AIR.

Дополнительные сведения об улучшении производительности повторяемых действий см. в следующих статьях.

Признак анимации

Старайтесь не использовать анимацию, так как для ее обработки требуется много ресурсов ЦП и памяти, что сокращает время работы от аккумулятора.

Дизайнеры и разработчики, создающие Flash-приложения для настольных компьютеров, часто используют анимацию движения. При создании содержимого для мобильных устройств старайтесь свести анимацию к минимуму. Без анимации приложения будет быстрее работать на низкопроизводительных устройствах.