【问题标题】:Does Exoplayer2 always cause onSurfaceSizeChanged() to be called at least twice?Exoplayer2 是否总是导致 onSurfaceSizeChanged() 至少被调用两次?
【发布时间】:2020-11-13 15:58:48
【问题描述】:

我的应用使用了一个自定义 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 的大小和位置。

【问题讨论】:

    标签: android-layout exoplayer2.x


    【解决方案1】:

    我最初的问题的简单答案似乎是:否 - 无法保证在正常渲染管道中调用了多少次,除非它至少被调用一次。

    经过进一步测试,很明显,即使在使用 STATE_READY 调用 onPlayerStateChanged() 之后,视频大小仍不稳定(我已经看到很多次了,即使在 STATE_READY 获取后,onSurfaceSizeChanged() 也会使用更新的值调用调用)。

    所以我最初的想法是在 playWhenReady 为 TRUE 之后处理 onPlayerStateChanged() 中的所有内容现在似乎不是一个好的答案。

    仍在寻找如何判断视频表面已稳定到它认为“最终”播放视频的大小!

    作为复习,我自定义的 FrameLayout 具有三个“层”(每个层都完全填充与当前 ViewPager2 适配器关联的持有者):

    1. 媒体显示(图像的 Glide 实现,或媒体的 ExoPlayer2 PlayerView)
    2. DrawView(自定义的 FrameLayout,它包含在顶部绘制的各种形状)
    3. FrameLayout(当来自 Internet 的视频媒体需要一段时间来缓冲时,会显示不确定的进度条和文本)

    我的解决方案最终是(在 ViewPager2 recyclerview 中的“下一个”项目准备好显示视频时):

    1. 最初隐藏 DrawView 和 Media Display 层
    2. 显示“加载”组件
    3. ExoPlayer 上的 setPlayerWhenReady(true)
    4. 准备(媒体数据源)
    5. 在我的活动实现的 ExoPlayer 的 onPlayerStateChanged() 回调中,测试 playWhenReady 是否为 TRUE 和 plabackState 是否为 STATE_READY,然后
    6. 移除“加载”视图
    7. 设置 ExoPlayer 视图可见
    8. 根据 ExoPlayer 的 videoSurfaceView 尺寸和位置计算 DrawView 中的各种绘图小部件
    9. 设置 DrawView 可见。

    我不知道为什么,但似乎覆盖其他回调,如来自 VideoListener 的回调并没有“慢跑”视图以正确绘制自己。我看到很多情况下,DrawView 类的 onDraw() 会被调用,但小部件的 onDraw 和 DrawView 类的 onDispatchDraw 都不会被调用。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-02-16
      • 1970-01-01
      • 2021-11-26
      • 1970-01-01
      • 2014-02-10
      • 2021-12-27
      • 2012-07-01
      相关资源
      最近更新 更多