2014-02-07 93 views
9

更改播放器的dataSource时,我遇到Android MediaPlayer问题。根据MediaPlayerhttp://developer.android.com/reference/android/media/MediaPlayer.html)的规格,我必须在更换dataSource时玩家reset。这很好,但只要连续两次调用channelChanged方法,MediaPlayer.reset就会冻结UI。我分析代码如下所示:Android MediaPlayer重置冻结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)); 
} 

复位:3

的setDataSource:1

制备:0

复位:3119

的setDataSource:2

准备:1

所以显然reset由第一通话asynchronous preparing(当我等到第一个流开始,然后再次调用channelChanged(),一切都很好)受阻。

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

还有其他什么好的解决方案吗?

+0

做,如果你插入一个电话'你得到什么行为在“重置”调用之前立即释放?它应该取消准备(我以为'重置'会做同样的...)。 – Dave

+1

嗨,请原谅我迟到的答案。我不能在'release'后面调用'reset',也不能在'release'后调用任何'IllegalStateException'。但即使我尝试再次初始化MediaPlayer时,UI在调用'release'方法时也会冻结:(但值得一试 – Flixer

+0

啊,当然,你在'释放'之后不会调用任何东西。对不起,wasn不要想......我从来没有遇到任何一种阻塞方法的问题,但是,你能否确定它是版本还是设备特定的?另外,作为一般规则,在开始使用AsyncTask – Dave

回答

9

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语句,因为在某些设备/ OS版本中,MediaPlayer的是比别人差,有时它只是做怪异的东西。你应该有一个接口/监听器,它能够反应这些情况

UPDATE的:

这是当我停止我使用的方法(或暂停),我的音乐播放(主要来自示例应用程序采取,这是运行在一个服务,它已被修改,以适应我自己的应用程序,但仍然)。

第一种方法是通过两个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();   

    } 
} 

现在最核心的部分是下/跳过......

这是我做的......

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(); 
    } 
} 

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

祝你好运!让我知道如果有什么具体的你想看到的。

+2

感谢您的回答(对于我迟到的答案感到抱歉)。不幸的是,这并没有帮助我的情况,因为在重置MediaPlayer的同时执行AsyncPrepare时发生了UI冻结(我也尝试在线程中调用普通的'prepare'方法来让我自己实现'prepareAsync' - >也没有帮助)。无论是调用'reset'还是'release',它都不起作用 - 无论如何UI冻结都会发生。 – Flixer

+0

您是否尝试过调用重置然后创建一个新的MP实例? –

+1

我曾经做过一个应用程序,其唯一目的是将MediaPlayer方法按不同的顺序放置,并尽量避免使其崩溃。 –

0

最新的手机和Android API的作品多黄油,reset方法OD需要时(上一页下一页或)歌曲之间快速切换

所以对于旧的手机没有解决办法只有5-20毫秒,它只是它是如何工作