Сброс Android MediaPlayer замораживает пользовательский интерфейс
у меня проблема с Android MediaPlayer
при изменении dataSource
игрока. Согласно спецификации MediaPlayer
(http://developer.android.com/reference/android/media/MediaPlayer.html) я reset
игрок при смене dataSource
. Это работает нормально, но как только channelChanged
метод вызывается дважды в быстрой последовательности элементов MediaPlayer.reset
замораживает пользовательский интерфейс. Я профилирую код, как видно здесь:
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));
}
сброс: 3
setDataSource: 1
готовим: 0
сброс: 3119
setDataSource: 2
Готовим: 1
так видимо reset
заблокирован asynchronous preparing
первого вызова (когда я жду, пока не начнется первый поток, а затем вызовите
2 ответов
MediaPlayer-хитрый ублюдок. Я рекомендую вам взглянуть на пример приложения, где плохой дизайн 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 хуже, чем другие, и иногда он просто делает странные вещи. У вас должен быть интерфейс / слушатель, который способен реагировать на эти ситуации
обновление:
это метод, который я использую, когда я останавливаю (или приостанавливаю) воспроизведение музыки (в основном взятый из примера приложения, это работает в службе, и он был изменен в соответствии с моим собственным приложением но все же).
первый метод используется обоими stop
и pause
бывший передает 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();
}
}
теперь основная часть Следующая / пропустить...
вот что я делаю...
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 (найден в папке samples), и у меня не было проблема с ним.
это, как говорится, Я знаю, что вы имеете в виду, когда вы говорите, что все это заблокировано, я видел это, и это багги 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();
}
}
в качестве заключительного замечания я заметил ,что "медиаплеер блокирует все" происходит, когда аудиопоток или источник недоступна или ненадежна.
удачи! Дай мне знать, если захочешь увидеть что-то конкретное.
новейшие телефоны и Android API работает много масла,reset
метод занимает всего 5-20 мс при быстром переключении между песнями (next или prev)
таким образом, нет решения для старых телефонов, это просто, как это работает