SurfaceView и GLSurfaceView

Пользовательский интерфейс фреймворка приложения Android основан на иерархии объектов, которая начинается с View (Представления) . Все элементы пользовательского интерфейса проходят серию измерений и процесс компоновки, в результате которого они помещаются в прямоугольную область. Затем фреймворк отображает все видимые объекты представления на поверхности, настроенной WindowManager при выводе приложения на передний план. Поток пользовательского интерфейса приложения выполняет компоновку и рендеринг в буфере для каждого кадра.

SurfaceView

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

При рендеринге с использованием внешнего источника буферов, например, контекста GL или медиадекодера, необходимо копировать буферы из источника буферов для их отображения на экране. Использование SurfaceView позволяет это сделать.

Когда компонент представления SurfaceView готов стать видимым, фреймворк запрашивает у SurfaceControl новую поверхность из SurfaceFlinger. Для получения обратных вызовов при создании или уничтожении поверхности используйте интерфейс SurfaceHolder . По умолчанию фреймворк размещает вновь созданную поверхность за поверхностью пользовательского интерфейса приложения. Вы можете переопределить Z-порядок по умолчанию, чтобы поместить новую поверхность поверх.

Рендеринг с помощью SurfaceView полезен в случаях, когда требуется выполнить рендеринг на отдельной поверхности, например, при рендеринге с помощью API камеры или в контексте OpenGL ES. При рендеринге с помощью SurfaceView SurfaceFlinger напрямую компонует буферы на экране. Без SurfaceView необходимо компоновать буферы на внеэкранной поверхности, которая затем компонуется на экране, поэтому рендеринг с помощью SurfaceView устраняет дополнительную работу. После рендеринга с помощью SurfaceView используйте поток пользовательского интерфейса для координации с жизненным циклом активности и при необходимости корректируйте размер или положение представления. Затем Hardware Composer объединяет пользовательский интерфейс приложения и другие слои.

Новая поверхность является стороной-производителем BufferQueue, потребителем которой является слой SurfaceFlinger. Вы можете обновить поверхность, используя любой механизм, способный передавать данные в BufferQueue, например, функции Canvas, предоставляемые поверхностью, подключение EGLSurface и рисование на поверхности с помощью GLES или настройка медиадекодера для записи данных на поверхность.

SurfaceView и жизненный цикл активности

При использовании SurfaceView визуализируйте поверхность из потока, отличного от основного потока пользовательского интерфейса.

Для действия с SurfaceView существуют два отдельных, но взаимозависимых конечных автомата:

  • Приложение onCreate / onResume / onPause
  • Поверхность создана/изменена/уничтожена

При запуске активности вы получаете обратные вызовы в следующем порядке:

  1. onCreate()
  2. onResume()
  3. surfaceCreated()
  4. surfaceChanged()

Если вы нажмете «Назад», вы получите:

  1. onPause()
  2. surfaceDestroyed() (вызывается непосредственно перед исчезновением поверхности)

При повороте экрана активность сбрасывается и создаётся заново, и цикл повторяется. Быстрый перезапуск можно определить по функции isFinishing() . Активность может запускаться/останавливаться так быстро, что surfaceCreated() может произойти после onPause() .

Если нажать кнопку питания, чтобы очистить экран, вы получите только onPause() без surfaceDestroyed() . Поверхность останется активной, и рендеринг может продолжаться. Вы можете продолжать получать события Choreographer, если продолжите их запрашивать. Если у вас экран блокировки, который принудительно меняет ориентацию, ваша активность может быть перезапущена при восстановлении экрана устройства. В противном случае вы можете выйти из состояния «очищенного экрана» с той же поверхностью, что и раньше.

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

Запуск/остановка потока при запуске/остановке Activity хорошо сочетается с жизненным циклом приложения. Поток рендеринга запускается в onResume() и останавливается в onStop() . При создании и настройке потока иногда поверхность уже существует, иногда — нет (например, она всё ещё активна после переключения экрана кнопкой питания). Приходится дождаться создания поверхности перед инициализацией в потоке. Инициализацию в обратном вызове surfaceCreate() выполнить невозможно, поскольку он не сработает повторно, если поверхность не была создана заново. Вместо этого запросите или кэшируйте состояние поверхности и передайте его потоку рендеринга.

Запуск/остановка потока при создании/уничтожении поверхности работает хорошо, поскольку поверхность и рендерер логически переплетены. Поток запускается после создания поверхности, что позволяет избежать проблем с межпотоковым взаимодействием; сообщения о создании/изменении поверхности пересылаются. Чтобы убедиться, что рендеринг останавливается при гаснущем экране и возобновляется при его восстановлении, сообщите Choreographer о необходимости прекратить вызов обратного вызова отрисовки кадра. onResume() возобновляет обратные вызовы, если поток рендерера запущен. Однако, если анимация основана на прошедшем времени между кадрами, перед следующим событием может возникнуть большой промежуток; использование явного сообщения о паузе/возобновлении может решить эту проблему.

Оба варианта, независимо от того, привязан ли жизненный цикл потока к Activity или к поверхности, фокусируются на настройке потока рендеринга и на том, выполняется ли он. Связанная с этим проблема — извлечение состояния из потока при завершении активности (в onStop() или onSaveInstanceState() ); в таких случаях привязка жизненного цикла потока к активности работает лучше всего, поскольку после присоединения потока рендеринга к состоянию отрисованного потока можно получить доступ без примитивов синхронизации.

GLSurfaceView

Класс GLSurfaceView предоставляет вспомогательные классы для управления контекстами EGL, межпотокового взаимодействия и взаимодействия с жизненным циклом активности. Для использования GLES не требуется использовать GLSurfaceView.

Например, GLSurfaceView создаёт поток для рендеринга и настраивает в нём контекст EGL. Состояние автоматически очищается при приостановке активности. Большинству приложений не требуется никаких знаний об EGL для использования GLES с GLSurfaceView.

В большинстве случаев GLSurfaceView упрощает работу с GLES. В некоторых ситуациях он может даже мешать.

,

Пользовательский интерфейс фреймворка приложения Android основан на иерархии объектов, которая начинается с View (Представления) . Все элементы пользовательского интерфейса проходят серию измерений и процесс компоновки, в результате которого они помещаются в прямоугольную область. Затем фреймворк отображает все видимые объекты представления на поверхности, настроенной WindowManager при выводе приложения на передний план. Поток пользовательского интерфейса приложения выполняет компоновку и рендеринг в буфере для каждого кадра.

SurfaceView

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

При рендеринге с использованием внешнего источника буферов, например, контекста GL или медиадекодера, необходимо копировать буферы из источника буферов для их отображения на экране. Использование SurfaceView позволяет это сделать.

Когда компонент представления SurfaceView готов стать видимым, фреймворк запрашивает у SurfaceControl новую поверхность из SurfaceFlinger. Для получения обратных вызовов при создании или уничтожении поверхности используйте интерфейс SurfaceHolder . По умолчанию фреймворк размещает вновь созданную поверхность за поверхностью пользовательского интерфейса приложения. Вы можете переопределить Z-порядок по умолчанию, чтобы поместить новую поверхность поверх.

Рендеринг с помощью SurfaceView полезен в случаях, когда требуется выполнить рендеринг на отдельной поверхности, например, при рендеринге с помощью API камеры или в контексте OpenGL ES. При рендеринге с помощью SurfaceView SurfaceFlinger напрямую компонует буферы на экране. Без SurfaceView необходимо компоновать буферы на внеэкранной поверхности, которая затем компонуется на экране, поэтому рендеринг с помощью SurfaceView устраняет дополнительную работу. После рендеринга с помощью SurfaceView используйте поток пользовательского интерфейса для координации с жизненным циклом активности и при необходимости корректируйте размер или положение представления. Затем Hardware Composer объединяет пользовательский интерфейс приложения и другие слои.

Новая поверхность является стороной-производителем BufferQueue, потребителем которой является слой SurfaceFlinger. Вы можете обновить поверхность, используя любой механизм, способный передавать данные в BufferQueue, например, функции Canvas, предоставляемые поверхностью, подключение EGLSurface и рисование на поверхности с помощью GLES или настройка медиадекодера для записи данных на поверхность.

SurfaceView и жизненный цикл активности

При использовании SurfaceView визуализируйте поверхность из потока, отличного от основного потока пользовательского интерфейса.

Для действия с SurfaceView существуют два отдельных, но взаимозависимых конечных автомата:

  • Приложение onCreate / onResume / onPause
  • Поверхность создана/изменена/уничтожена

При запуске активности вы получаете обратные вызовы в следующем порядке:

  1. onCreate()
  2. onResume()
  3. surfaceCreated()
  4. surfaceChanged()

Если вы нажмете «Назад», вы получите:

  1. onPause()
  2. surfaceDestroyed() (вызывается непосредственно перед исчезновением поверхности)

При повороте экрана активность сбрасывается и создаётся заново, и цикл повторяется. Быстрый перезапуск можно определить по функции isFinishing() . Активность может запускаться/останавливаться так быстро, что surfaceCreated() может произойти после onPause() .

Если нажать кнопку питания, чтобы очистить экран, вы получите только onPause() без surfaceDestroyed() . Поверхность останется активной, и рендеринг может продолжаться. Вы можете продолжать получать события Choreographer, если продолжите их запрашивать. Если у вас экран блокировки, который принудительно меняет ориентацию, ваша активность может быть перезапущена при восстановлении экрана устройства. В противном случае вы можете выйти из состояния «очищенного экрана» с той же поверхностью, что и раньше.

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

Запуск/остановка потока при запуске/остановке Activity хорошо сочетается с жизненным циклом приложения. Поток рендеринга запускается в onResume() и останавливается в onStop() . При создании и настройке потока иногда поверхность уже существует, иногда — нет (например, она всё ещё активна после переключения экрана кнопкой питания). Приходится дождаться создания поверхности перед инициализацией в потоке. Инициализацию в обратном вызове surfaceCreate() выполнить невозможно, поскольку он не сработает повторно, если поверхность не была создана заново. Вместо этого запросите или кэшируйте состояние поверхности и передайте его потоку рендеринга.

Запуск/остановка потока при создании/уничтожении поверхности работает хорошо, поскольку поверхность и рендерер логически переплетены. Поток запускается после создания поверхности, что позволяет избежать проблем с межпотоковым взаимодействием; сообщения о создании/изменении поверхности пересылаются. Чтобы убедиться, что рендеринг останавливается при гаснущем экране и возобновляется при его восстановлении, сообщите Choreographer о необходимости прекратить вызов обратного вызова отрисовки кадра. onResume() возобновляет обратные вызовы, если поток рендерера запущен. Однако, если анимация основана на прошедшем времени между кадрами, перед следующим событием может возникнуть большой промежуток; использование явного сообщения о паузе/возобновлении может решить эту проблему.

Оба варианта, независимо от того, привязан ли жизненный цикл потока к Activity или к поверхности, фокусируются на настройке потока рендеринга и на том, выполняется ли он. Связанная с этим проблема — извлечение состояния из потока при завершении активности (в onStop() или onSaveInstanceState() ); в таких случаях привязка жизненного цикла потока к активности работает лучше всего, поскольку после присоединения потока рендеринга к состоянию отрисованного потока можно получить доступ без примитивов синхронизации.

GLSurfaceView

Класс GLSurfaceView предоставляет вспомогательные классы для управления контекстами EGL, межпотокового взаимодействия и взаимодействия с жизненным циклом активности. Для использования GLES не требуется использовать GLSurfaceView.

Например, GLSurfaceView создаёт поток для рендеринга и настраивает в нём контекст EGL. Состояние автоматически очищается при приостановке активности. Большинству приложений не требуется никаких знаний об EGL для использования GLES с GLSurfaceView.

В большинстве случаев GLSurfaceView упрощает работу с GLES. В некоторых ситуациях он может даже мешать.