任务二 播放 MV 并管理播放器
接下来在 VideoActivity 中接入 Media3 ExoPlayer,播放歌曲对应的 MV。离开页面时暂停视频,页面销毁时释放播放器。
一、任务目标
完成后,视频页面将能够:
- 使用
PlayerView承载视频画面。 - 创建 ExoPlayer,设置
MediaItem并播放在线 MV。 - 根据播放器状态更新视频准备和结束结果。
- 离开页面时暂停视频,销毁页面时释放播放器。
二、配置 Media3 依赖
1. 认识 ExoPlayer 和 PlayerView
2. 添加依赖
打开 app/build.gradle.kts,在 dependencies 中加入 ExoPlayer 和 PlayerView 依赖。
dependencies { // ... 省略已有依赖。 implementation("androidx.media3:media3-exoplayer:1.2.1") implementation("androidx.media3:media3-ui:1.2.1")}同步 Gradle 后,应用即可使用 Media3 的播放器和界面组件。
三、替换视频容器
打开 activity_video.xml,将任务一的 FrameLayout 替换为 PlayerView,并关闭组件自带控制器,后续使用自定义控件。
<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 并保存播放器引用。
import androidx.media3.exoplayer.ExoPlayer
class VideoActivity : AppCompatActivity() { private lateinit var binding: ActivityVideoBinding private var player: ExoPlayer? = null
// ... 省略已有代码。}2. 根据 MV 地址创建播放器
MV 地址已在任务一存入 mvUrl。在 onCreate() 末尾调用 prepareVideo(),并在类中添加该方法。
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() 中创建播放器后添加监听器。视频播放结束时回到起点,并暂停播放。
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 画面并开始播放,如下图所示。播放结束后,视频应回到起点并暂停。
五、离开页面时暂停并释放播放器
现在视频已经能播放,但离开视频页面后,如果不处理,声音可能继续播放;页面关闭后,播放器也可能继续占用设备资源。接下来让视频在页面不可见时暂停,并在页面销毁时释放播放器。
1. 页面停止时暂停
点击返回或把应用切到后台时,VideoActivity 会执行 onStop()。在这个方法中暂停视频,避免离开页面后仍能听到声音。
class VideoActivity : AppCompatActivity() { // ... 省略已有代码。
override fun onStop() { super.onStop() player?.pause() }}2. 页面销毁时释放
页面销毁时,在 onDestroy() 中释放 ExoPlayer,并清空引用。再次进入视频页面时,prepareVideo() 会创建新的播放器。
class VideoActivity : AppCompatActivity() { // ... 省略已有代码。
override fun onDestroy() { player?.release() player = null super.onDestroy() }}3. 验证离开与再次进入
进入视频页面并等待 MV 播放,然后依次检查:
- 返回歌曲列表后,视频声音是否停止。
- 再次打开同一首 MV,是否能重新播放。
- 将应用切到后台后,视频声音是否停止。
任务小结
视频页面现在能播放在线 MV,并在离开页面时暂停、销毁时释放播放器。下一任务补充播放控制和进度显示。