gpt4 book ai didi

java - Android MediaPlayer 重置卡住 UI

转载 作者:塔克拉玛干 更新时间:2023-11-02 08:29:29 26 4
gpt4 key购买 nike

更改播放器的 dataSource 时,Android MediaPlayer 出现问题。根据 MediaPlayer ( http://developer.android.com/reference/android/media/MediaPlayer.html ) 的规范,我必须在更改 dataSource重置播放器。这工作正常,但是一旦 channelChanged 方法被快速连续调用两次,MediaPlayer.reset 就会卡住 UI。我分析了这里看到的代码:

public void channelChanged(String streamingUrl)
{
long m1 = System.currentTimeMillis();
mMediaPlayer.reset();
long m2 = System.currentTimeMillis();
try
{
mMediaPlayer.setDataSource(streamingUrl);
}
catch (IOException e)
{
e.printStackTrace();
}
long m3 = System.currentTimeMillis();
mMediaPlayer.prepareAsync();
long m4 = System.currentTimeMillis();
Log.d("MEDIAPLAYER", "reset: " + (m2 - m1));
Log.d("MEDIAPLAYER", "setDataSource: " + (m3 - m2));
Log.d("MEDIAPLAYER", "preparing: " + (m4 - m3));
}

reset: 3

setDataSource: 1

preparing: 0

reset: 3119

setDataSource: 2

preparing: 1

显然 reset 被第一次调用的 asynchronous preparing 阻塞了(当我等到第一个流开始然后调用 channelChanged() 再一次,一切都很好)。

有什么解决问题的办法吗?我应该在一个单独的线程中执行整个方法吗?基本上我想避免这种情况,因为它似乎不是一种好的编码风格,并且可能会导致一些进一步的问题,例如当用户尝试再次启动播放器时,但播放器仍处于 reset 方法中,另一方面似乎在等待 asyncPrepare 方法。目前尚不清楚玩家会如何表现......

还有其他好的解决办法吗?

最佳答案

MediaPlayer 是个狡猾的 SCSS 。我建议您看一下示例应用程序,通过查看您必须围绕它编写的困惑代码才能获得一致的媒体播放体验,从中可以看出 MediaPlayer 的糟糕设计。

如果有的话,在查看示例后,您会发现当他们想要跳过轨道时,他们实际上是重置并释放......

    mPlayer.reset();
mPlayer.release();

...稍后当他们准备加载新轨道时...

    try {
mPlayer.reset();
mPlayer.setDataSource(someUrl);
mPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
@Override
public void onPrepared(MediaPlayer mediaPlayer) {
//bam!
}
});
mPlayer.prepareAsync();
} catch (IllegalStateException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
}

我已经添加了 try/catch,因为在某些设备/操作系统版本上,MediaPlayer 比其他的更糟糕,有时它只会做一些奇怪的事情。你应该有一个能够对这些情况使用react的接口(interface)/监听器

更新:

这是我在停止(或暂停)我的音乐播放时使用的方法(主要取自示例应用程序,它在服务中运行,并且已经过修改以适合我自己的应用程序,但仍然如此)。

第一个方法被stoppause都使用,前者传true,后者传false

/**
* Releases resources used by the service for playback. This includes the "foreground service"
* status and notification, the wake locks and possibly the MediaPlayer.
*
* @param releaseMediaPlayer Indicates whether the Media Player should also be released or not
*/
void relaxResources(boolean releaseMediaPlayer) {
stopForeground(true);
stopMonitoringPlaybackProgress();
// stop and release the Media Player, if it's available
if (releaseMediaPlayer && mPlayer != null) {
mPlayer.reset();
mPlayer.release();
mPlayer = null;
}
// we can also release the Wifi lock, if we're holding it
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);//notify broadcast receivers
relaxResources(false); // while paused, we always retain the mp and notification

这是 processStopRequest() 的一部分(已简化):

void processStopRequest(boolean force, final boolean stopSelf) {
if (mState == State.Playing || mState == State.Paused || force) {
mState = State.Stopped;
// let go of all resources...
relaxResources(true);
currentTrackNotification = null;
giveUpAudioFocus();

}
}

现在核心部分是next/skip...

这就是我所做的......

void processNextRequest(final boolean isSkipping) {
processStopRequest(true, false); // THIS IS IMPORTANT, WE RELEASE THE MP HERE
mState = State.Retrieving;
dispatchBroadcastEvent(ServiceConstants.EVENT_TRACK_INFO_LOAD_START);
// snipped but here you retrieve your next track and when it's ready…
// you just processPlayRequest() and "start from scratch"

MediaPlayer 示例就是这样做的(位于示例文件夹中),我没有遇到任何问题。

话虽这么说,当你说你把整个事情都封锁了时,我知道你的意思,我已经看到了,这是 MP 错误。如果您收到 ANR,我想查看它的日志。

为了记录,这里是我“开始玩”的方式(很多自定义代码已被省略,但您可以看到 MP 内容):“

/**
* Starts playing the next song.
*/
void beginPlaying(Track track) {
mState = State.Stopped;
relaxResources(false); // release everything except MediaPlayer
try {
if (track != null) {
createMediaPlayerIfNeeded();
mPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
mPlayer.setDataSource(track.audioUrl);
} else {
processStopRequest(true, false); // stop everything!
return;
}
mState = State.Preparing;
setUpAsForeground(); //service

/* STRIPPED ALL CODE FROM REMOTECONTROLCLIENT, AS IT ADDS A LOT OF NOISE :) */

// starts preparing the media player in the background. When it's done, it will call
// our OnPreparedListener (that is, the onPrepared() method on this class, since we set
// the listener to 'this').
// Until the media player is prepared, we *cannot* call start() on it!
mPlayer.prepareAsync();
// We are streaming from the internet, we want to hold a Wifi lock, which prevents
// the Wifi radio from going to sleep while the song is playing.
if (!mWifiLock.isHeld()) {
mWifiLock.acquire();
}

} catch (IOException ex) {
Log.e("MusicService", "IOException playing next song: " + ex.getMessage());
ex.printStackTrace();
}
}

最后一点,我注意到当音频流或源不可用或不可靠时,会发生“媒体播放器阻止一切”。

祝你好运!让我知道您是否希望看到任何具体内容。

关于java - Android MediaPlayer 重置卡住 UI,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21631998/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com