接下来说明一下,提供歌词播放器服务的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;
- }
接下来是播放控制关联方法。主要做以下几件事
- @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();
- }
- }