
1. ExoPlayer 播放状态监听概述
在 ExoPlayer 中,监听播放器的状态变化是实现动态 UI 更新和逻辑控制的基础。ExoPlayer 提供了 Player.Listener 接口(在旧版本中为 Player.DefaultEventListener),通过实现该接口中的回调方法,可以捕获播放器的各种状态事件。
核心概念包括:
- playWhenReady: 一个布尔值,表示播放器是否应该在准备就绪时立即开始播放。true 表示播放器被“期望”播放,false 表示被“期望”暂停。这不代表播放器当前正在播放。
- playbackState: 一个整数值,表示播放器当前的内部状态,例如 STATE_IDLE(空闲)、STATE_BUFFERING(缓冲中)、STATE_READY(准备就绪)和 STATE_ENDED(播放结束)。
要准确判断播放器是处于“播放中”还是“已暂停”状态,通常需要结合这两个参数进行判断,或者利用 ExoPlayer 2.12 及更高版本提供的更直接的 API。
2. 核心方法:区分播放与暂停
2.1 推荐方法:使用 Player.Listener.onIsPlayingChanged(boolean isPlaying) (ExoPlayer 2.12+)
对于 ExoPlayer 2.12 及更高版本,最直接、最清晰的判断播放状态的方法是监听 onIsPlayingChanged 回调。当媒体实际开始播放或停止播放(包括暂停)时,此方法会被调用。
- isPlaying 为 true:表示媒体正在主动播放。
- isPlaying 为 false:表示媒体已暂停、停止、缓冲中但未开始播放、或处于其他非播放状态。
示例代码 (Kotlin):
player.addListener(object : Player.Listener {
override fun onIsPlayingChanged(isPlaying: Boolean) {
super.onIsPlayingChanged(isPlaying)
if (isPlaying) {
// 媒体正在播放
// 更新UI为播放状态,例如显示暂停按钮
println("ExoPlayer: 正在播放")
} else {
// 媒体已暂停或停止
// 更新UI为暂停状态,例如显示播放按钮
println("ExoPlayer: 已暂停/停止")
}
}
})示例代码 (Java):
player.addListener(new Player.Listener() {
@Override
public void onIsPlayingChanged(boolean isPlaying) {
Player.Listener.super.onIsPlayingChanged(isPlaying); // 兼容性调用
if (isPlaying) {
// 媒体正在播放
// 更新UI为播放状态,例如显示暂停按钮
System.out.println("ExoPlayer: 正在播放");
} else {
// 媒体已暂停或停止
// 更新UI为暂停状态,例如显示播放按钮
System.out.println("ExoPlayer: 已暂停/停止");
}
}
});2.2 兼容方法:结合 onPlayWhenReadyChanged 和 onPlaybackStateChanged
对于需要更细粒度控制或兼容旧版本 ExoPlayer 的场景,可以同时监听 onPlayWhenReadyChanged 和 onPlaybackStateChanged。
- onPlayWhenReadyChanged(playWhenReady: Boolean, reason: Int): 当播放器的 playWhenReady 属性改变时触发。
- onPlaybackStateChanged(playbackState: Int): 当播放器的内部 playbackState 改变时触发。
要判断是否正在播放或已暂停,需要综合这两个状态:
- 正在播放: playWhenReady 为 true 且 playbackState 为 Player.STATE_READY 或 Player.STATE_BUFFERING。
- 已暂停: playWhenReady 为 false 且 playbackState 为 Player.STATE_READY 或 Player.STATE_BUFFERING 或 Player.STATE_IDLE。
示例代码 (Kotlin):
player.addListener(object : Player.Listener {
override fun onPlaybackStateChanged(playbackState: Int) {
super.onPlaybackStateChanged(playbackState)
updatePlayPauseUI(player.playWhenReady, playbackState)
}
override fun onPlayWhenReadyChanged(playWhenReady: Boolean, reason: Int) {
super.onPlayWhenReadyChanged(playWhenReady, reason)
updatePlayPauseUI(playWhenReady, player.playbackState)
}
private fun updatePlayPauseUI(playWhenReady: Boolean, playbackState: Int) {
if (playWhenReady && (playbackState == Player.STATE_READY || playbackState == Player.STATE_BUFFERING)) {
// 媒体正在播放(或即将播放)
println("ExoPlayer: 正在播放 (基于 playWhenReady 和 playbackState)")
// 更新UI为播放状态
} else if (!playWhenReady && (playbackState == Player.STATE_READY || playbackState == Player.STATE_BUFFERING || playbackState == Player.STATE_IDLE)) {
// 媒体已暂停
println("ExoPlayer: 已暂停 (基于 playWhenReady 和 playbackState)")
// 更新UI为暂停状态
} else if (playbackState == Player.STATE_ENDED) {
// 播放结束
println("ExoPlayer: 播放结束")
// 更新UI为播放结束状态
}
}
})2.3 旧版方法:使用 Player.DefaultEventListener.onPlayerStateChanged(boolean playWhenReady, int playbackState) (已弃用)
在 ExoPlayer 2










