MediaPlayer是一个棘手的家伙。我建议你看一下示例应用程序,通过查看你必须编写的混乱代码来实现一致的媒体播放体验,从而明确了MediaPlayer的糟糕设计。
如果有什么不同,看完示例后,你会发现当他们想要跳过一个曲目时,实际上是重置并释放...
mPlayer.reset();
mPlayer.release();
...然后当他们准备加载新的音轨时...
try {
mPlayer.reset();
mPlayer.setDataSource(someUrl);
mPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
@Override
public void onPrepared(MediaPlayer mediaPlayer) {
}
});
mPlayer.prepareAsync();
} catch (IllegalStateException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
}
由于一些设备/操作系统版本上的MediaPlayer比其他设备更糟糕,有时它会出现奇怪的问题,因此我已经添加了try/catch。 您应该拥有一个能够对这些情况做出反应的接口/监听器。
更新:
这是我停止(或暂停)音乐播放时使用的方法(大多数来自示例应用程序,这在服务中运行,并已修改以适合我的应用程序,但仍然)。
第一个方法由stop和pause都使用,前者传递true,后者传递false。
void relaxResources(boolean releaseMediaPlayer) {
stopForeground(true);
stopMonitoringPlaybackProgress();
if (releaseMediaPlayer && mPlayer != null) {
mPlayer.reset();
mPlayer.release();
mPlayer = null;
}
if (mWifiLock.isHeld()) {
mWifiLock.release();
}
}
这是processPauseRequest()
的一部分:
if (mState == State.Playing) {
// Pause media player and cancel the 'foreground service' state.
mState = State.Paused
mPlayer.pause()
dispatchBroadcastEvent(ServiceConstants.EVENT_AUDIO_PAUSE)
relaxResources(false)
这是processStopRequest()
的一部分(简化版):
void processStopRequest(boolean force, final boolean stopSelf) {
if (mState == State.Playing || mState == State.Paused || force) {
mState = State.Stopped;
relaxResources(true);
currentTrackNotification = null;
giveUpAudioFocus();
}
}
现在核心部分是下一步/跳过...
这是我所做的...
void processNextRequest(final boolean isSkipping) {
processStopRequest(true, false);
mState = State.Retrieving;
dispatchBroadcastEvent(ServiceConstants.EVENT_TRACK_INFO_LOAD_START);
这是MediaPlayer示例的实现方式(在样例文件夹中找到),我使用过并没有问题。
话虽如此,当你说整个东西被阻塞时,我知道你的意思,我也见过它,那是由于MediaPlayer的漏洞。如果你遇到ANR错误,我想看看相关日志。
记录一下,以下是我“开始播放”的代码(省略了许多自定义代码,但你能看到有关MediaPlayer的部分):
void beginPlaying(Track track) {
mState = State.Stopped;
relaxResources(false);
try {
if (track != null) {
createMediaPlayerIfNeeded();
mPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
mPlayer.setDataSource(track.audioUrl);
} else {
processStopRequest(true, false);
return;
}
mState = State.Preparing;
setUpAsForeground();
mPlayer.prepareAsync();
if (!mWifiLock.isHeld()) {
mWifiLock.acquire();
}
} catch (IOException ex) {
Log.e("MusicService", "IOException playing next song: " + ex.getMessage());
ex.printStackTrace();
}
}
作为最后的说明,我注意到当音频流或来源不可用或不可靠时,“媒体播放器阻止一切”的情况会发生。
祝你好运!让我知道你想要看到什么特定的内容。
reset
之前立即插入对release
的调用,会出现什么行为?它应该会取消准备工作(我原以为reset
会做同样的事情...)。 - Daverelease
之后调用reset
,也无法在release
之后调用任何东西而不会出现IllegalStateException
异常。即使我尝试重新初始化MediaPlayer,在调用release
方法时UI界面也会冻结:( 但是这个尝试还是值得的。 - Flixerrelease
之后调用任何东西。抱歉,我没有考虑到这一点...虽然我从来没有遇到过这两种方法阻塞的问题。你能确定是版本还是设备特定的吗?另外,作为一个通则,启动一个AsyncTask
来处理这类任务并将其从UI线程中移出是没有问题的。任何可能会阻塞的调用都应该在不同的线程上执行。 - Dave