Всегда ли Exoplayer2 вызывает вызов onSurfaceSizeChanged() как минимум дважды?

#android-layout #exoplayer2.x

#android-layout #exoplayer2.x

Вопрос:

Мое приложение использует настраиваемый FrameLayout, который содержит PlayerView и другой пользовательский FrameLayout («DrawView»). Цель состоит в том, чтобы нарисовать настраиваемые фигуры в FrameLayout, которые появляются поверх воспроизводимого видео.

В макете сначала у меня есть PlayerView, затем DrawView:

 <!-- customized FrameLayout encompassing ViewPager2 and DrawView, which implements that capability of
         detecting taps -->
<com.reddragon.intouch.utils.ViewPager2Host
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@ id/viewpager2host"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#000000"
    tools:context=".ui.MediaPlayerActivity">

    <androidx.viewpager2.widget.ViewPager2
        android:id="@ id/activity_media_player_viewpager"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
    </androidx.viewpager2.widget.ViewPager2>

    <com.reddragon.intouch.ui.drawview.DrawView
        android:id="@ id/drawView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>
  

DrawView Компонент используется для рисования фигур и текста поверх видео, поэтому мне нужно изменить его размер в соответствии с размером и положением прямоугольника, который представляет, где воспроизводится видео.

Для этого у меня правильно реализована логика, и я реализовал VideoListener и поместил эту логику внутри onSurfaceSizeChanged() .

Это работает нормально — и, как вы можете видеть на скриншоте, красная линия (представляющая границы окружающего родительского ViewPager2Host) и зеленая линия (представляющие границы / расположение видеоповерхности, которые я рассчитал во время выполнения для этого конкретного видео) верны:

введите описание изображения здесь

Вот мой вопрос — onSurfaceSizeChanged() вызывается несколько раз, и я хочу выполнить вычисление размера и местоположения только один раз DrawView . Из моего тестирования видно, что до тех пор, пока ViewPager2Host родительский элемент не изменяет размеры, он onSurfaceSizeChanged() вызывается дважды, а второй раз является «конечным» измерением.

Кто-нибудь может подтвердить, что это так? Или есть случаи — возможно, когда родительские размеры точно соответствуют размеру видеоповерхности, который onSurfaceSizeChanged() будет вызываться только один раз?

Или есть какой-то способ узнать, когда размер поверхности является «окончательным»?

Я пытаюсь реализовать какую-то логику «если видео инициализируется, то», чтобы только ПОСЛЕ завершения всего макета и завершения прямой видеоповерхности я вычислял размер и размещение DrawView.

Ответ №1:

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

При дальнейшем тестировании также становится ясно, что даже после вызова onPlayerStateChanged() с помощью STATE_READY размер видео еще не стабилен (я уже много раз видел, что onSurfaceSizeChanged() вызывается с обновленными значениями даже после вызова STATE_READY).

Итак, моя первоначальная идея обрабатывать все в onPlayerStateChanged() после того, как playWhenReady имеет значение TRUE, теперь не кажется хорошим ответом.

Все еще ищу, как я могу определить, что поверхность видео уменьшилась до размера, который, по его мнению, является «окончательным» для воспроизведения видео!

В качестве обновления мой настраиваемый FrameLayout имеет три «слоя» (каждый из которых полностью заполняет держатель, связанный с текущим адаптером ViewPager2):

  1. Отображение мультимедиа (либо реализация Glide для изображений, либо ExoPlayer2 PlayerView для мультимедиа)
  2. DrawView (настраиваемый FrameLayout, который содержит различные фигуры, нарисованные сверху)
  3. FrameLayout (содержит неопределенный индикатор выполнения и текст, отображаемый, когда для буферизации видеоматериалов из Интернета требуется некоторое время)

Мое решение закончилось тем, что (после того, как элемент «next» в ViewPager2 recyclerview был готов к отображению видео):

  1. Изначально скройте слои DrawView и Media Display
  2. Показать «загружаемые» компоненты
  3. Установите playerwhenready(true) на ExoPlayer
  4. подготовка (mediaDataSource)
  5. В обратном вызове onPlayerStateChanged() из ExoPlayer, который реализует моя activity, проверьте, что значение playWhenReady равно TRUE, а значение plabackState равно STATE_READY, а затем
  6. удалите «загрузочные» представления
  7. установите вид ExoPlayer видимым
  8. вычислите различные виджеты для рисования в DrawView с учетом размеров и положения videoSurfaceView ExoPlayer
  9. установите видимый вид.

Я не уверен почему, но, похоже, переопределение других обратных вызовов, таких как из VideoListener, не «подталкивало» представления к правильному рисованию. Я видел множество случаев, когда вызывалась onDraw() класса DrawView, но ни onDraw виджетов, ни onDispatchDraw класса DrawView не вызывались.