Android歌詞秀設計思路(5)歌詞播放服務 – Android移動開發技術文章_手機開發 Android移動開發教學課程

接下來說明一下,提供歌詞播放器服務的LyricPlayerService。這個類在整個播放過程中的作用是
1.負責管理LyricAdapter的生命周期。
2.控制音樂播放,歌詞解析,並且協調音樂與歌詞同步。
3.收集超類,LyricAdapter發來的通知並傳遞給登錄的LyricAdapterListener
首先是看一下這個類在全體圖中的位置。

 
從圖中我們可以明顯的看出這個類處於整個圖中的節點位置,光從這一點就可以理解這個類的重要性。
代碼不多,簡單說明一下。
首先是定義用於從LyricPlayerService接收狀態變化通知的接口並提供瞭指定具象接口的方法。
在歌曲播放過程中,繼續應用退出LyricPlayerService還會繼續執行。這時如果重新啟動播放器應用程序,就有一個重新建立聯系,也就是播放中的LyricPlayerService指定接口的場景。在LyricPlayerService的設計中,會重新調用LyricPlayerListener的onLyricLoad和onLyricChanged方法。這樣應該可以簡化應用側的實現。
    //定義接受播放器狀態變化的接口 
    public interface LyricPlayerListener{ 
        //播放位置發生變化 
        public void onPositionChanged(long position); 
        //播放器狀態發生變化 
        public void onStateChanged(); 
        //當前歌詞變化 
        public void onLyricChanged(int lyric_index); 
        //歌詞文件解析完瞭 
        public void onLyricLoaded(); 
    } 
     
    private LyricPlayerListener mLyricPlayerListener = null; 
     
    void setLyricPlayerListener(LyricPlayerListener listener){ 
        mLyricPlayerListener = listener; 
        if(mLyricPlayerListener != null) 
        { 
            //新設定Listener直接調用onLyricLoad方法,給以個準備表是內容的機會。 
            mLyricPlayerListener.onLyricLoaded(); 
            int curLyric = mLyricAdapter.getCurrentLyric(); 
            if(curLyric >= 0 && curLyric < mLyricAdapter.getLyricCount()){ 
                //如果已經處於播放中狀態,將現在歌詞通知給Listener 
                mLyricPlayerListener.onLyricChanged(curLyric); 
            } 
        } 
    }
創建LyricAdapter的實例
private LyricAdapter mLyricAdapter = new LyricAdapter();
創建SafetyTimer的實例並制定動作。在OnTimer事件中,首先取得MediaPlayer的現在播放位置並將這個信息通知給LyricAdapter和登錄的mLyricPlayerListener。內容很簡單,但是這裡是LyricPlayerService能夠正常動作的最主要的部分。除瞭我們看不到的歌曲播放部分,這裡差不多算是半個主程序瞭。
private SafetyTimer mLyricTimer = new SafetyTimer(500, new SafetyTimer.OnTimeListener(){ 
        public void OnTimer(){ 
            if(mMediaPlayer != null){ 
                int position = mMediaPlayer.getCurrentPosition(); 
                if(mLyricPlayerListener != null){ 
                    mLyricPlayerListener.onPositionChanged(position); 
                } 
                mLyricAdapter.notifyTime(position); 
            } 
        }    
    });
onCreate和onDestroy沒有什麼特別的。當然在onDestroy裡面也可以調用mLyricAdapter.setListener(null); 沒有什麼區別。
@Override
    public void onCreate() { 
        super.onCreate(); 
        mLyricAdapter.setListener(this); 
    } 
 
    @Override
    public void onDestroy() { 
        super.onDestroy(); 
        mLyricAdapter = null; 
    }
接下來是播放控制關聯方法。主要做以下幾件事
1.調用超類的功能。
2.控制SafetyTimer的動作。
3.條用Listener的對應功能。
 
@Override
    public void start() { 
        if(isStop()){ 
            //停止狀態開始,需要重新啟動Timer 
            super.start(); 
            mLyricTimer.startTimer(); 
        }else{ 
            //暫停狀態開始,不需要重啟Timer 
            super.start(); 
        } 
        if(mLyricPlayerListener != null){ 
            mLyricPlayerListener.onStateChanged(); 
        } 
    }    
     
    @Override
    public void stop() { 
        mLyricTimer.stopTimer(); 
        super.stop(); 
        if(mLyricPlayerListener != null){ 
            mLyricPlayerListener.onStateChanged(); 
        } 
    }    
     
    @Override
    public void pause() { 
        super.pause(); 
        if(mLyricPlayerListener != null){ 
            mLyricPlayerListener.onStateChanged(); 
        } 
    }    
 
下面的兩個方法覆蓋瞭,超類的對應方法,把本來用來播放前後歌曲的功能改成播放同一首歌內的前後一句歌詞。
@Override
   public void playNext(){ 
    seekToNextLyric(); 
   } 
    
   @Override
   public void playPrev(){ 
    seekToPrevLyric(); 
   }
以下是有關歌詞的方法。基本上都是利用LyricAdapter和超類的位置控制功能。
public void loadLyric(){ 
        String url = getDataSource(); 
        //和歌曲在同一目錄下,相同文件名,擴展名為lrc的文件 
        String strLyricFileUrl = url.substring(0, url.lastIndexOf(".") + 1) + "lrc"; 
        mLyricAdapter.LoadLyric(strLyricFileUrl); 
    } 
     
    public int getLyricCount(){ 
        return mLyricAdapter.getLyricCount(); 
    } 
     
    public String getLyric(int index){ 
        return mLyricAdapter.getLyric(index); 
    } 
     
    public long seekToLyric(int index){ 
        long position = mLyricAdapter.getLyricTime(index); 
        if(position != -1){ 
            return seek(position); 
        }else{ 
            return 0; 
        } 
    } 
     
    public void seekToPrevLyric(){ 
        int curLyric =  mLyricAdapter.getCurrentLyric(); 
        if(curLyric > 0){ 
            seekToLyric(curLyric – 1); 
        } 
    } 
     
    public void seekToNextLyric(){ 
        int curLyric =  mLyricAdapter.getCurrentLyric(); 
        if(curLyric < mLyricAdapter.getLyricCount() – 1){ 
            seekToLyric(curLyric + 1); 
        } 
    }
所剩不多瞭,重載onCompletion是想在這個時刻關閉Timer的同時,將這一變化通知個mLyricPlayerListener.
@Override
public void onCompletion(MediaPlayer mp) { 
    if(mLyricTimer.isRunging()){ 
        mLyricTimer.stopTimer(); 
    } 
    if(mLyricPlayerListener != null){ 
        mLyricPlayerListener.onStateChanged(); 
    } 
    super.onCompletion(mp); 
}  
最後是繼承LyricAdapter.LyricListener需要的兩個方法。將來自LyricAdapter的通知轉送給已經登錄的mLyricPlayerLister。之所以這樣做是希望利用者在使用時可以簡單一些。
@Override
    public void onLyricChanged(int lyric_index){ 
        if(mLyricPlayerListener != null){ 
            mLyricPlayerListener.onLyricChanged(lyric_index); 
        } 
    } 
     
    @Override
    public void onLyricLoaded(){ 
        if(mLyricPlayerListener != null){ 
            mLyricPlayerListener.onLyricLoaded(); 
            mLyricPlayerListener.onStateChanged(); 
        } 
    }
軟件功能說明:原創:Android應用開發-Andorid歌詞秀,含源碼
工程,源碼下載:Android歌詞秀源碼,工程文件2011/9/11版
作者“來自大連”

發佈留言