向应用添加播放控件

播放媒体的应用需要界面组件来显示媒体和控制播放。Media3 库包含一个界面模块,其中包含多个界面组件。如需依赖于界面模块,请添加以下依赖项:

Kotlin

implementation("androidx.media3:media3-ui:1.5.0")

Groovy

implementation "androidx.media3:media3-ui:1.5.0"

其中最重要的组件是 PlayerView,它是一个用于媒体播放的视图。PlayerView 会在播放期间显示视频、图片、字幕和专辑封面,以及播放控件。

PlayerView 提供了一个 setPlayer 方法,用于附加和分离(通过传递 null)玩家实例。

PlayerView

PlayerView 可用于视频、图片和音频播放。它会在视频播放时渲染视频和字幕,在图片播放时渲染位图,还可以显示作为元数据包含在音频文件中的海报图片。您可以像任何其他界面组件一样将其添加到布局文件中。例如,PlayerView 可包含在以下 XML 中:

<androidx.media3.ui.PlayerView
    android:id="@+id/player_view"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:show_buffering="when_playing"
    app:show_shuffle_button="true"/>

上面的代码段说明了 PlayerView 提供了多个属性。这些属性可用于自定义视图的行为以及外观和风格。其中大多数属性都有对应的 setter 方法,可用于在运行时自定义视图。PlayerView Javadoc 详细列出了这些属性和 setter 方法。

在布局文件中声明视图后,您可以在 activity 的 onCreate 方法中查找该视图:

Kotlin

override fun onCreate(savedInstanceState: Bundle?) {
  super.onCreate(savedInstanceState)
  // ...
  playerView = findViewById(R.id.player_view)
}

Java

@Override
protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  // ...
  playerView = findViewById(R.id.player_view);
}

初始化播放器后,可以通过调用 setPlayer 将其附加到视图:

Kotlin

// Instantiate the player.
val player = ExoPlayer.Builder(context).build()
// Attach player to the view.
playerView.player = player
// Set the media item to be played.
player.setMediaItem(mediaItem)
// Prepare the player.
player.prepare()

Java

// Instantiate the player.
player = new ExoPlayer.Builder(context).build();
// Attach player to the view.
playerView.setPlayer(player);
// Set the media item to be played.
player.setMediaItem(mediaItem);
// Prepare the player.
player.prepare();

选择 Surface 类型

借助 PlayerViewsurface_type 属性,您可以设置用于视频播放的 Surface 类型。除了值 spherical_gl_surface_view(球形视频播放的特殊值)和 video_decoder_gl_surface_view(用于使用扩展程序渲染程序渲染视频)之外,允许的值还包括 surface_viewtexture_viewnone。如果视图仅用于音频播放,则应使用 none,以避免创建 Surface,因为这样做可能会很耗费资源。

如果视图用于常规视频播放,则应使用 surface_viewtexture_view。与 TextureView 相比,SurfaceView 在视频播放方面具有多项优势:

  • 在许多设备上显著降低功耗
  • 帧时间更准确,视频播放更流畅。
  • 支持在支持的设备上输出更高质量的 HDR 视频。
  • 支持在播放受 DRM 保护的内容时进行安全输出。
  • 在放大界面层的 Android TV 设备上,能够以显示屏的完整分辨率渲染视频内容。

因此,应尽可能优先使用 SurfaceView,而不是 TextureView。只有在 SurfaceView 无法满足您的需求时,才应使用 TextureView。例如,在 Android 7.0(API 级别 24)之前,需要视频 Surface 的流畅动画或滚动,如以下备注所述。对于这种情况,最好仅在 SDK_INT 小于 24(Android 7.0)时使用 TextureView,否则使用 SurfaceView

Android TV 上的方向键导航

Android TV 的遥控器有一个方向键控件,用于发送命令,这些命令会作为按键事件传送到 ActivitydispatchKeyEvent(KeyEvent)。这些事件需要委托给播放器视图:

Kotlin

override fun dispatchKeyEvent(event: KeyEvent?): Boolean{
  return playerView.dispatchKeyEvent(event!!) || super.dispatchKeyEvent(event)
}

Java

@Override
public boolean dispatchKeyEvent(KeyEvent event) {
  return playerView.dispatchKeyEvent(event) || super.dispatchKeyEvent(event);
}

为播放器视图请求焦点对于浏览播放控制器和跳过广告非常重要。考虑在 ActivityonCreate 中请求焦点:

Kotlin

override fun onCreate(savedInstanceState: Bundle?) {
  super.onCreate(savedInstanceState)
  // ...
  playerView.requestFocus()
  // ...
}

Java

@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    // ...
    playerView.requestFocus();
    // ...
}

如果您在 Android TV 上使用 Compose,则需要相应地将修饰符参数传递给 AndroidView,以使 AndroidView 可聚焦并委托事件:

AndroidView(
  modifier = modifier
    .focusable()
    .onKeyEvent { playerView.dispatchKeyEvent(it.nativeKeyEvent) },
  factory = { playerView }
)

替换可绘制对象

PlayerView 使用 PlayerControlView 显示播放控件和进度条。PlayerControlView 使用的可绘制对象可以被应用中定义的具有相同名称的可绘制对象替换。如需查看可替换的控件可绘制对象的列表,请参阅 PlayerControlView Javadoc。

进一步自定义

如果需要进行上述以外的自定义,我们希望应用开发者实现自己的界面组件,而不是使用 Media3 界面模块提供的组件。