任务二 播放 MV 并管理播放器

接下来在 VideoActivity 中接入 Media3 ExoPlayer,播放歌曲对应的 MV。离开页面时暂停视频,页面销毁时释放播放器。

一、任务目标

完成后,视频页面将能够:

  • 使用 PlayerView 承载视频画面。
  • 创建 ExoPlayer,设置 MediaItem 并播放在线 MV。
  • 根据播放器状态更新视频准备和结束结果。
  • 离开页面时暂停视频,销毁页面时释放播放器。

二、配置 Media3 依赖

1. 认识 ExoPlayer 和 PlayerView

2. 添加依赖

打开 app/build.gradle.kts,在 dependencies 中加入 ExoPlayer 和 PlayerView 依赖。

app/build.gradle.kts
dependencies {
// ... 省略已有依赖。
implementation("androidx.media3:media3-exoplayer:1.2.1")
implementation("androidx.media3:media3-ui:1.2.1")
}

同步 Gradle 后,应用即可使用 Media3 的播放器和界面组件。

三、替换视频容器

打开 activity_video.xml,将任务一的 FrameLayout 替换为 PlayerView,并关闭组件自带控制器,后续使用自定义控件。

app/src/main/res/layout/activity_video.xml
<androidx.constraintlayout.widget.ConstraintLayout ...>
<FrameLayout
android:id="@+id/video_container"
android:layout_width="0dp"
android:layout_height="0dp"
android:background="@android:color/black"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<androidx.media3.ui.PlayerView
android:id="@+id/player_view"
android:layout_width="0dp"
android:layout_height="0dp"
android:background="@android:color/black"
app:resize_mode="fit"
app:surface_type="texture_view"
app:use_controller="false"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<!-- ... 省略其他控件。 -->
</androidx.constraintlayout.widget.ConstraintLayout>

texture_view 能在当前页面布局中保持较好的兼容性,use_controller="false" 为后续自定义控制栏预留空间。

四、创建并准备 ExoPlayer

1. 添加播放器成员

打开 VideoActivity.kt,导入 ExoPlayer 并保存播放器引用。

app/src/main/java/com/sziit/musicplayer/ui/activity/VideoActivity.kt
import androidx.media3.exoplayer.ExoPlayer
class VideoActivity : AppCompatActivity() {
private lateinit var binding: ActivityVideoBinding
private var player: ExoPlayer? = null
// ... 省略已有代码。
}

2. 根据 MV 地址创建播放器

MV 地址已在任务一存入 mvUrl。在 onCreate() 末尾调用 prepareVideo(),并在类中添加该方法。

app/src/main/java/com/sziit/musicplayer/ui/activity/VideoActivity.kt
import androidx.media3.common.MediaItem
class VideoActivity : AppCompatActivity() {
// ... 省略已有成员。
override fun onCreate(savedInstanceState: Bundle?) {
// ... 省略已有代码。
binding.imgBack.setOnClickListener { finish() }
prepareVideo()
}
private fun prepareVideo() {
if (mvUrl.isEmpty()) return
player = ExoPlayer.Builder(this).build().also { exoPlayer ->
binding.playerView.player = exoPlayer
exoPlayer.setMediaItem(MediaItem.fromUri(mvUrl))
exoPlayer.prepare()
exoPlayer.play()
}
}
}

prepare() 开始加载媒体数据,play() 设置播放请求,视频准备完成后便会自动播放。地址为空时直接返回,不向播放器传入空地址。

3. 监听播放器状态

在 prepareVideo() 中创建播放器后添加监听器。视频播放结束时回到起点,并暂停播放。

app/src/main/java/com/sziit/musicplayer/ui/activity/VideoActivity.kt
import androidx.media3.common.Player
class VideoActivity : AppCompatActivity() {
// ... 省略已有代码。
private fun prepareVideo() {
// ... 省略地址检查。
player = ExoPlayer.Builder(this).build().also { exoPlayer ->
binding.playerView.player = exoPlayer
exoPlayer.setMediaItem(MediaItem.fromUri(mvUrl))
exoPlayer.prepare()
exoPlayer.play()
exoPlayer.addListener(object : Player.Listener {
override fun onPlaybackStateChanged(playbackState: Int) {
if (playbackState == Player.STATE_ENDED) {
exoPlayer.seekTo(0)
exoPlayer.pause()
}
}
})
}
}
}

下一任务会在这个监听器中补充视频时长和进度显示。

4. 验证视频播放

运行应用,点击有 MV 的歌曲,确认视频页面出现 MV 画面并开始播放,如下图所示。播放结束后,视频应回到起点并暂停。

MV 视频播放效果

五、离开页面时暂停并释放播放器

现在视频已经能播放,但离开视频页面后,如果不处理,声音可能继续播放;页面关闭后,播放器也可能继续占用设备资源。接下来让视频在页面不可见时暂停,并在页面销毁时释放播放器。

1. 页面停止时暂停

点击返回或把应用切到后台时,VideoActivity 会执行 onStop()。在这个方法中暂停视频,避免离开页面后仍能听到声音。

app/src/main/java/com/sziit/musicplayer/ui/activity/VideoActivity.kt
class VideoActivity : AppCompatActivity() {
// ... 省略已有代码。
override fun onStop() {
super.onStop()
player?.pause()
}
}

2. 页面销毁时释放

页面销毁时,在 onDestroy() 中释放 ExoPlayer,并清空引用。再次进入视频页面时,prepareVideo() 会创建新的播放器。

app/src/main/java/com/sziit/musicplayer/ui/activity/VideoActivity.kt
class VideoActivity : AppCompatActivity() {
// ... 省略已有代码。
override fun onDestroy() {
player?.release()
player = null
super.onDestroy()
}
}

3. 验证离开与再次进入

进入视频页面并等待 MV 播放,然后依次检查:

  1. 返回歌曲列表后,视频声音是否停止。
  2. 再次打开同一首 MV,是否能重新播放。
  3. 将应用切到后台后,视频声音是否停止。

任务小结

视频页面现在能播放在线 MV,并在离开页面时暂停、销毁时释放播放器。下一任务补充播放控制和进度显示。