假设有两个线程:我的线程和 MediaPlayer 线程(通过 looper 向我发送消息)。我的游戏线程对用户输入做出反应:如果用户暂停游戏,我也会调用 MediaPlayer.pause()。
考虑以下事件顺序:
- MediaPlayer 音频流到达终点,因此它将 OnCompletion 消息排入队列给我
- 我的线程:MediaPlayer.pause() 由于用户操作而被调用
- 我收到 OnCompletion 调用(为时已晚,上面已经调用了 pause())
这样做的问题是 MediaPlayer.pause() 只允许在 PAUSED 和 STARTED 状态下,但是由于第 1 步,当调用 pause() 时 MediaPlayer 已经处于 PlaybackCompleted 状态。我看到两个解决方案:
- 捕捉异常
- 在调用 pause() 之前询问 MediaPlayer.isPlaying()
但是第二种方案在以下场景中存在问题:
- 游戏开始,MediaPlayer.start() 被调用,但媒体播放器状态 尚未开始
- 用户离开游戏,调用代码: if(isPlaying()) pause();
- MediaPlayer 进入 STARTED 状态(现在 isPlaying 将返回 true,但为时已晚)
这里的问题是 isPlaying() 仍将返回 false (正如文档所说),因此 MediaPlayer 仍将由于第 3 步而启动。
是否有正确的解决方案并在这两种情况下都避免异常?(或者我上面的思路有什么错误吗?)
更新
对 Geobits 的回答做出反应(我在这里这样做是因为我会引用 Android 文档):
是的,我也在做本地播放,和你一样测试了很多,一切看起来都很好。但是文档有点自相矛盾。第一部分(这没关系):
调用 start() 为暂停的 MediaPlayer 对象恢复播放,恢复的播放位置与暂停的位置相同。当对 start() 的调用返回时,暂停的 MediaPlayer 对象将返回 Started 状态。
来自同一页面的另一句话:
播放可以暂停和停止,当前播放位置可以调整。可以通过 pause() 暂停播放。当对 pause() 的调用返回时,MediaPlayer 对象进入 Paused 状态。请注意,从 Started 状态到 Paused 状态的转换(反之亦然)在播放器引擎中异步发生。在对 isPlaying() 的调用中更新状态可能需要一些时间,在流式内容的情况下可能需要几秒钟。
后者表示,当启动暂停播放器时,状态更改可能需要时间(“反之亦然”)。到目前为止一切都很好,因为它仅适用于内部播放器引擎,但随后出现了疯狂的部分:“在调用 isPlaying() 时更新状态可能需要一些时间”。这意味着 isPlaying()没有返回 OBSERVABLE 状态,而是取决于内部状态。这令人困惑。