onCompletion()正常情況下是在一首歌曲播放完之后會得到調(diào)用,但是現(xiàn)在發(fā)現(xiàn)有時候會異常調(diào)用,找了一些資料,發(fā)現(xiàn)如果在mediaplayer setDataSource之前就調(diào)用了類似 getDuration()的方法就會出錯,onCompletion()就會被調(diào)用。
那么為什么會出現(xiàn)在在setDataSource之前就調(diào)用了類似getDuration()的方法呢?我的項目中是這樣的情況:
我自定義了一個View顯示播放的信息(就是最下面的那個)

下面的進度信息是通過新開了一個線程,不斷地通過getDuration()來獲取歌曲進度的,但是當我們快速點擊list上面的歌曲的時候,歌曲在切換的瞬間(即當mediaplayer reset之后,setDataSource之前),那個線程來不及反應(yīng)還沒停止繼續(xù)在getDuration(),所以會有很大的幾率出現(xiàn)onCompletion()被異常調(diào)用的情況。
那么怎么解決?我們onCompletion()本身要完成的是切換下一首歌曲同時更新下面的自定義View信息,但是現(xiàn)在onCompletion()被異常調(diào)用,就會出現(xiàn)我明明點的是第一首歌,但是自定義View上顯示的卻是下一首歌的信息,這個就很尷尬了。
解決方法是:onCompletion()里面進行判斷,如果當前狀態(tài)是播放或者暫停情況下,onCompletion()被調(diào)用,就不更新View!因為我點擊list上的歌曲之前我的mediaplayer只有2種可能性,要么播放started,要么paused,其他狀態(tài)點擊list上的歌曲不會出現(xiàn)異常調(diào)用onCompletion()的可能,而我們正常情況下一首歌播放完切換下一首歌的時候mediaplayer的狀態(tài)不會是started或者paused,那么現(xiàn)在問題又來了,怎么獲取當前mediaplayer狀態(tài),mediaplayer本身是沒有這個方法的,只有isPlaying判斷是否在播放,對于我們呢沒有用,所以我們自己需要加一個狀態(tài)碼,在每次mediaplayer狀態(tài)切換的時候?qū)@個狀態(tài)碼進行修改
public int MEDIA_PLAYER_MODE=0;
//播放模式:0——Idle 1——Initialized 3——Prepared 4——Started 5--Paused 6——Stopped
@Override
public void onCompletion(MediaPlayer mp)
{
Log.d("sendError","MusicService.onCompletion()"+"mp.isPlaying()?"+mp.isPlaying());
//歌曲在播放的時候調(diào)用到了這個方法,說明出了問題!不進行后續(xù)處理!
if(!mp.isPlaying()&&(MEDIA_PLAYER_MODE==4||MEDIA_PLAYER_MODE==5))
{
switch (PLAY_MODE)
{
//列表循環(huán)模式
case 0:
//處理本身邏輯
if(curPos==songs.size()-1) //到底了重新開始播放
{
curPos=0;
}
_toNextSong();
_sendToNextMessage();
break;
//順序播放模式
case 1:
//處理本身邏輯
if(curPos==songs.size()-1) //到底了就停止播放
{
_realeaseMediaPlayer();
return;
}
_toNextSong(); //切換下一首歌
_sendToNextMessage(); //更新View
break;
case 2:
break;
case 3:
break;
default:
break;
}
}
}
這里的Idle Initialized 都是mnediaplayer的生命周期,這里附上mediaplayer生命周期圖:
