Android歌词秀设计思路(3)通用的音乐播放服务(上)

MediaPlayerService作为通用的音乐播放Service类,它的功能有:

  1. 控制音乐播放,停止,暂停,前/后歌曲切换。
  2. Audio Focus相关处理(对应应用程序切换)。
  3. Intent处理(对应多媒体键,耳机线拔出,打入电话)
  4. Notification处理

其实这个类本来是和LyricPlayerService在一起的,但是随着功能的增加代码越来越乱。于是就有了分开的想法。但是分也要分出点名堂,于是为这个类定义的功能就是实现一个通用的媒体播放服务。

分开后的类关系可以从下面的全体图中看出。 

Android歌词秀设计思路(3)通用的音乐播放服务(上)_第1张图片

下面针对各功能加以说明

控制音乐播放,停止,暂停,前/后歌曲切换。

在开始真正的工作之前要解决的一个问题是:作为通用的音乐播放那个服务,就一定会还有在后台时播放前/后一首歌的要求。但是这是应用已经不存在了,不可能把这个任务交个Activie来处理。为了解决这个问题定义了一个用于取得相应的媒体文件信息的MediaInfoProvider类。

  
  
  
  
  1. public interface MediaInfoProvider{  
  2.     String getUrl();  
  3.     String getTitle();  
  4.     boolean moveToNext();  
  5.     boolean moveToPrev();  

通过调用moveToNext和moveToPrev方法实现媒体文件的切换,然后通过调用getUrl和getTitle来取得文件的信息。

注意在这里只是规定接口,真正的实例必须由利用者通过下面的方法来提供。有一点额外的工作就是如果希望播放的歌曲和正在播放的不一样的话就先停止正在播放的歌曲。 

  
  
  
  
  1. public void setMediaInfoProvider(MediaInfoProvider provider) {    
  2.     if( mDataSource != provider.getUrl() && (isStop() == false)){  
  3.         stop();  
  4.     }  
  5.     mMediaInfoProvider = provider;  
  6.     mDataSource = provider.getUrl();  
  7.     mTitle = provider.getTitle();  
  8. }  

当然在利用MediaPlayer之前我们需要onCreate方法中进行一些准备工作。内容包括

  1. 创建MediaPlayer对象,
  2. 设定唤醒方式(目的是防止播放中CPU进入休眠状态,记得在 AndroidManifest.xml中设定权限为android.permission.WAKE_LOCK)
  3. 指定播放完了后的监听器。
  
  
  
  
  1. mMediaPlayer = new MediaPlayer();  
  2. mMediaPlayer.setWakeMode(getApplicationContext(), PowerManager.PARTIAL_WAKE_LOCK);  
  3. mMediaPlayer.setOnCompletionListener(this);
 

这个播放完了监听器的目的有两个。一个是停止任务栏上的图标显示,另外一个是在没有前台应用的时候自动关闭本服务。要是没有人管了怎么办?对吧。

  
  
  
  
  1. @Override
  2. public void onCompletion(MediaPlayer mp) {
  3. mIsPausing = false;
  4. mNotificationManager.cancel(NOTIFICATION);
  5. if(mBinded == false){
  6. stopSelf();
  7. }
  8. }

然后就是onDestroy中进行适当的收尾工作。其中停止播放的部分看起来好像没有也可以,还是一切都按部就班好一些吧。

  
  
  
  
  1. mMediaPlayer.setOnCompletionListener(null);  
  2. if(!isStop()){  
  3.     stop();  
  4. }  
  5. mMediaPlayer.release();  
  6. mMediaPlayer = null

 终于到到了真正的控制部分。接下来的程序比较长但内容确实比较简单。

在最前面的start方法比较复杂,主要是因为虽然说起来都是播放,但是从暂停恢复播放和播放新歌的处理有所不同。其他的没有什么好讲的。

  
  
  
  
  1. public void start() {  
  2.         tryToGetAudioFocus();  
  3.         if(!isPausing()){  
  4.             if(isPlaying()){  
  5.                 stop();  
  6.             }  
  7.             try{     
  8.                 mMediaPlayer.reset();     
  9.                 mMediaPlayer.setDataSource(mDataSource);     
  10.                 mMediaPlayer.prepare();   
  11.             }catch(IOException e) {     
  12.                 return;     
  13.             } catch  (IllegalArgumentException e) {     
  14.                 return;     
  15.             }     
  16.             mMediaPlayer.start();  
  17.         }else{  
  18.             mIsPausing = false;  
  19.             mMediaPlayer.start();  
  20.         }  
  21.         showNotification();  
  22.     }     
  23.       
  24.     public void stop() {  
  25.         giveUpAudioFocus();  
  26.         mMediaPlayer.stop();    
  27.         mIsPausing = false;  
  28.         mNotificationManager.cancel(NOTIFICATION);  
  29.     }     
  30.       
  31.     public void pause() {  
  32.         giveUpAudioFocus();  
  33.         mIsPausing = true;  
  34.         mMediaPlayer.pause();  
  35.     }  
  36.       
  37.     public void playNext(){  
  38.         if(mMediaInfoProvider.moveToNext()){  
  39.             if(isPlaying() || isPausing()){  
  40.                 stop();  
  41.             }  
  42.             mDataSource = mMediaInfoProvider.getUrl();  
  43.             mTitle = mMediaInfoProvider.getTitle();  
  44.             start();  
  45.         }  
  46.     }  
  47.       
  48.     public void playPrev(){  
  49.         if(mMediaInfoProvider.moveToPrev()){  
  50.             if(isPlaying() || isPausing()){  
  51.                 stop();  
  52.             }  
  53.             mDataSource = mMediaInfoProvider.getUrl();  
  54.             mTitle = mMediaInfoProvider.getTitle();  
  55.             start();  
  56.         }  
  57.     }  
  58.       
  59.     public boolean isPausing(){  
  60.         return mIsPausing;  
  61.     }  
  62.       
  63.     public boolean isPlaying() {     
  64.         return mMediaPlayer.isPlaying();     
  65.     }    
  66.       
  67.     public boolean isStop(){  
  68.         return (isPlaying() == false && isPausing() == false);  
  69.     }  
  70.       
  71.     public int getDuration() {     
  72.         return mMediaPlayer.getDuration();     
  73.     }     
  74.          
  75.     public int getPosition() {     
  76.         return mMediaPlayer.getCurrentPosition();     
  77.     }     
  78.       
  79.     public long seek(long whereto) {  
  80.         mMediaPlayer.seekTo((int ) whereto);  
  81.         return whereto;  
  82.     } 

下面的代码的功能是处理各种有关播放控制的Intent。媒体键(就是其实就是线控上的那几个钮),耳机线拔出,来电暂停都是通过这种方式实现的。当然它们都需要在AndroidManifest.xml中进行定义。

  
  
  
  
  1. public static final String ACTION_PAUSE = "MediaPlayer.xwg.action.PAUSE";  
  2. public static final String ACTION_PLAY_PAUSE = "MediaPlayer.xwg.action.PLAY_PAUSE";  
  3. public static final String ACTION_PREVIOUS = "MediaPlayer.xwg.action.PREVIOUS";  
  4. public static final String ACTION_NEXT = "MediaPlayer.xwg.action.NEXT";  
  5.    @Override 
  6. public int onStartCommand(Intent intent, int flags, int startId) {  
  7.     String action = intent.getAction();  
  8.     if(action != null)  
  9.     {  
  10.         if (action.equals(ACTION_PLAY_PAUSE)){  
  11.             if(isPlaying()){  
  12.                 pause();  
  13.             }else{  
  14.                 start();  
  15.             }  
  16.         }else if (action.equals(ACTION_PAUSE)){  
  17.             if(isPlaying())  
  18.             {  
  19.                 pause();  
  20.             }  
  21.         }else if (action.equals(ACTION_PREVIOUS)){  
  22.             if(isPlaying() || isPausing())  
  23.             {  
  24.                 playPrev();  
  25.             }  
  26.         }else if (action.equals(ACTION_NEXT)){  
  27.             if(isPlaying() || isPausing())  
  28.             {  
  29.                 playNext();  
  30.             }  
  31.         }  
  32.     }  
  33.        return START_NOT_STICKY; // Means we started the service, but don't want it to  
  34.            // restart in case it's killed.  

其实在前面代码中的有几个地方没有提,就是关于AudioFocus和MEDIA_BUTTOn,,耳机插头拔出,来电处理和Notification表示的部分。关于这部分内容请参阅

你可能感兴趣的:(android,工作,null,action,音乐,任务)