在項目中有這樣一個需求呼畸,就是在列表中點擊一首歌會跳到歌曲的詳情頁進行播放,關(guān)于音頻播放常用的做法就是用service來進行播放,activity與service直接建立一個中間人對象,通過中間人來控制音樂的播放與暫停或者上一首锌蓄,下一首。
在播放代碼中一般對MediaPlayer對象進行如下設(shè)置:
mediaPlayer.setDataSource(url);
mediaPlayer.setOnPreparedListener(mOnPreparedListener);
mediaPlayer.setOnCompletionListener(mOnCompletionListener);
mediaPlayer.setOnErrorListener(mOnErrorListener);
mediaPlayer.prepareAsync();
在實際運用過程中發(fā)現(xiàn)當我點擊第一首播放的時候撑柔,會自動播放下一首瘸爽,第一首不會播放。對播放的監(jiān)聽里面打log發(fā)現(xiàn)铅忿,一開始播放第一首的時候直接不會走PreparedListener的監(jiān)聽而是直接走了CompletionListener的監(jiān)聽剪决。但是當我在當前界面而不進入詳情頁,通過startService來進行播放的時候就沒有問題檀训。
然后進行谷歌昼捍,上面說prepareAsync( )方法是一個異步操作,用prepared( )方法才會走PreparedListener的監(jiān)聽肢扯,遂將prepareAsync()方法改為prepared( )妒茬。這個時候問題貌似解決了,但是后面還有更大的坑在等著我蔚晨。乍钻。。铭腕。
因為prepared( )在主線程中是個耗時操作银择,原先的時候在音樂詳情頁的activity中oncreat( )下通過bindservice 跟 startservice來進行音樂的播放。當我們點擊當前列表條目的時候累舷,需要等待4 5 秒才能進入音樂詳情頁進行音樂的播放浩考。
很顯然這樣是不符合我們的預期的,經(jīng)過打斷點調(diào)試發(fā)現(xiàn)問題就出在startservice( )調(diào)用之后再在service里面的mediaplayer調(diào)用prepared( )方法所致被盈。當時開發(fā)比較緊張析孽,先用handler的postdelayed( )方法延遲500毫秒加載startService( )方法。
至此可以現(xiàn)在打開音樂詳情的界面只怎,然后進行播放了袜瞬。但是這樣也是治標不治本,prepared( )還是運行在主線程身堡,等待播放的時候還是需要等待4 5 秒鐘邓尤,很容易造成ANR。并且在測試環(huán)境下,有可能后臺給的歌曲地址不正確播放不出來的時候汞扎,app就會假死季稳,盡管我設(shè)置了出錯的監(jiān)聽。
本質(zhì)上還是要把prepared( )方法改為prepareAsync( )澈魄,經(jīng)老大研究別的開源項目指點景鼠,將CompletionListener放在PreparedListener里面,代碼如下:
mediaPlayer.setDataSource(url);
mediaPlayer.prepareAsync();
mediaPlayer.setOnPreparedListener(mOnPreparedListener);
mediaPlayer.setOnErrorListener(mOnErrorListener);
private MediaPlayer.OnPreparedListener mOnPreparedListener = new MediaPlayer.OnPreparedListener( ) {
@Override
public void onPrepared(MediaPlayer mp) {
OnCompletionListener(mOnCompletionListener);
}
};
自我感覺的話應(yīng)該是異步的時候還沒準備好就直接進行CompletionListener了一忱,上面代碼這樣操作的時候就相當于準備好了以后才能進行播放完成的監(jiān)聽。
因為音頻播放的問題相對來說開發(fā)的比較少谭确,谷歌的很多都是基礎(chǔ)的播放問題帘营,還是需要自己多多琢磨啊。
前人栽樹后人乘涼逐哈,以后就會少走很多彎路芬迄,共勉