在ExoPlayer中检测暂停/恢复

43

我在Github上搜索了两天,但没有找到确切的答案。我想要一个在ExoPlayer > 2.x中检测暂停/恢复的例子。有人可以给我一个例子吗?我已经检查了onPlayerStateChanged,但问题没有解决。

onPlayerStateChanged   :   STATE_BUFFERING 
onPlayerStateChanged   :   STATE_READY 

我刚刚从onPlayerStateChanged获取了这个日志,但并不总是调用!

11个回答

81

请参考Player.isPlaying()方法,该方法作为API提供。

"而不是需要单独检查这些属性,可以调用Player.isPlaying。"

https://exoplayer.dev/listening-to-player-events.html#playback-state-changes

您需要使用Player.EventListener来检查playWhenReady。 ExoPlayer的播放状态与播放器是否暂停无关:

player.addListener(new Player.DefaultEventListener() {
  @Override
  public void onPlayerStateChanged(boolean playWhenReady, int playbackState) {
    if (playWhenReady && playbackState == Player.STATE_READY) {
      // media actually playing
    } else if (playWhenReady) {
      // might be idle (plays after prepare()), 
      // buffering (plays when data available) 
      // or ended (plays when seek away from end)
    } else {
      // player paused in any state
    }
  }
});

要播放/暂停播放器,ExoPlayer 提供了

player.setPlayWhenReady(boolean)
ExoPlayer 在播放一个从未卡顿重新缓冲的媒体文件时,播放状态的序列为四种状态,且不包括播放/暂停状态。
Player.STATE_IDLE;
Player.STATE_BUFFERING;
Player.STATE_READY;
Player.STATE_ENDED;
每次玩家需要缓冲时,它会进行如下操作:
Player.STATE_READY;
Player.STATE_BUFFERING;
Player.STATE_READY;

设置playWhenReady不会影响状态。

总之,当您的媒体正在播放时

playWhenReady && playbackState == Player.STATE_READY

准备好时它会播放。 :)


这些常量现在已被标记为过时,但它们仍然可以使用,这对于调试非常有用。 - Ben
在dev-2分支(预发布版)中,STATE_XYZ常量并未被弃用。您认为这是为什么? - marcbaechinger
我正在使用Exo Player 2.7.0,而Android Studio告诉我这一点(目标API为27,向下兼容到16)- 我只是想留下一些信息,让大家知道它们仍在运作。我不确定“dev-2分支”。 - Ben
当我们在横屏模式下暂停视频并切换到竖屏模式时,此逻辑会失败。有什么解决办法吗? - Sandeep

16
您可以使用此函数:

public boolean isPlaying() {
    return exoPlayer.getPlaybackState() == Player.STATE_READY && exoPlayer.getPlayWhenReady();
}

16

自其他答案发布以来,Player.EventListener 提供了一种新的方法。[编辑:现在是 Player.Listener,因为 Player.EventListener 已弃用]。这对我非常有效:

override fun onIsPlayingChanged(isPlaying: Boolean) {
    // your code here
}
如果 isPlaying 为 false,则处于暂停状态,否则正在播放。

很遗憾,当视频结束时,这个功能不会被触发。 - m0skit0

6

Kotlin 2020 解决方案更新

诸如状态变化和播放错误之类的事件将报告给已注册的Player.EventListener 实例。

Player.EventListener 具有空默认方法,因此您只需要实现感兴趣的方法。

首先,您的类(例如活动)必须符合 Player.EventListener 接口。

然后,您在类上覆盖 onIsPlayingChanged 方法。onCreate 方法之外...

将监听器添加到您的播放器实例:

// Adding player listener for tracking events
player?.addListener(this)

您可以通过Player.isPlaying来检查播放器是否正在播放(即位置正在前进):

//Listening to player events
override fun onIsPlayingChanged(isPlaying: Boolean){
    if (isPlaying) {
        // Active playback.
    } else {
        // Not playing because playback is paused, ended, suppressed, or the player
        // is buffering, stopped or failed. Check player.getPlaybackState,
        // player.getPlayWhenReady, player.getPlaybackError and
        // player.getPlaybackSuppressionReason for details.
    }
}

就是这样。非常简单。


6
我有同样的需求,需要检测exoplayer的播放/暂停按钮点击事件。前面的回答主要是讨论状态而不是按钮点击事件。
以下是我用于检测播放/暂停按钮点击的方法,效果完美。
步骤1:创建自定义控制分发器类并重写dispatchSetPlayWhenReady方法。
class PlayerControlDispatcher : DefaultControlDispatcher() {
    override fun dispatchSetPlayWhenReady(player: Player?, playWhenReady: Boolean): Boolean {
        if(playWhenReady) {
           // Play button clicked
        } else {
          // Paused button clicked
        }
        return super.dispatchSetPlayWhenReady(player, playWhenReady)
    }
}

步骤 2:将自定义控制分发器类 PlayerControlDispatcher 设置到播放器视图中。
playerView.setControlDispatcher(PlayerControlDispatcher())

playerView 是我们在布局文件中声明的 com.google.android.exoplayer2.ui.PlayerView 的实例。


1
这是正确的答案,完美地运行!谢谢@krishna-sharma! - renatoarg
很高兴看到它对你有用 @renatoarg,现在它将帮助其他人解决这个问题。 - Krishna Sharma
嗨@KrishnaSharma,我尝试了你的代码但是出现了错误。你能解释一下我应该把代码放在哪个位置吗? - HiDayurie Dave
@HiDayurieDave 你可以把它放在任何地方,可以创建独立的类或内部类。重要的一行是playerView.setControlDispatcher(PlayerControlDispatcher())。 - Krishna Sharma
1
ControlDispatcher接口已在2.16.0中删除,请参见https://github.com/google/ExoPlayer/releases/tag/r2.16.0。 - Thomas McGuire
1
binding.playerView.findViewById<View>(R.id.exo_play_pause).setOnClickListener { } 这段代码也可用于检测播放/暂停按钮的点击事件。 - Mohd Haseen

2
你可以使用exoplayer.getPlayWhenReady()来检查播放器当前是否处于暂停状态或播放状态。最初的回答。

2

使用2.16.1版本时,我使用以下代码:

exoPlayer.addListener(object : Player.Listener {
    override fun onIsPlayingChanged(isPlaying: Boolean) {
        if (isPlaying){
            videoIsPlaying()
        }
    }
})

2

I think the callback:

fun onPlayWhenReadyChanged(playWhenReady: Boolean, reason: Int)

来自于 Player.Listener


是的,它对我真的有效!它在用户播放或暂停媒体时才会被调用。 - Ali Zahid

1
请尝试以下代码片段。播放器监听器(onPlayerStateChanged)不能很好地观察播放/暂停动作,因为它被多次调用,并且在播放器配置时也会被调用。
videoView.setControlDispatcher(object : DefaultControlDispatcher() {
            override fun dispatchSetPlayWhenReady(player: Player, playWhenReady: Boolean): Boolean {
                if (playWhenReady)
                  // Tap on Play button  
                else
                 // Tap on Pause button
                return super.dispatchSetPlayWhenReady(player, playWhenReady)
            }
        })

1
ControlDispatcher接口已在2.16.0中被移除,请参见github.com/google/ExoPlayer/releases/tag/r2.16.0。 - Thomas McGuire

0

您必须使用新版本:com.google.android.exoplayer:exoplayer:2.18.6

此函数已过时:

@Deprecated
    default void onPlayerStateChanged(boolean playWhenReady, @State int playbackState) {}

新功能是:

 default void onPlaybackStateChanged(@State int playbackState) {}

例如:

exoPlayer?.addListener(object : Player.Listener {
            override fun onPlaybackStateChanged(@Player.State state: Int) {
                when (state) {
                    Player.STATE_READY -> {
                        // The player is able to immediately play from its current position. The player will be playing if getPlayWhenReady() is true, and paused otherwise.
                    }
                    Player.STATE_BUFFERING -> {
                       // The player is not able to immediately play the media, but is doing work toward being able to do so. This state typically occurs when the player needs to buffer more data before playback can start.
                    }
                    Player.STATE_IDLE -> {
                       // The player is idle, meaning it holds only limited resources.The player must be prepared before it will play the media.
                    }
                    Player.STATE_ENDED -> { 
                       // The player has finished playing the media.
                    }
                    else -> {
                      // Other things
                    }
                }
            }
        })

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接