Android 音乐播放器的实现(二)Service的实现

Android 界一直流传着一句话,想学习Service, 那么你就要写一个音乐播放器。 

为什么要用 Service?

Service 是运行于幕后的,它并不轻易见人,而正巧,音乐也是只闻其声不见其人的,相信这就是它们在一起的原因。

大家都知道,从Activity中跟Service交互有两种方式:

1)startService。在Activity 中直接调用 startService的方法,我们就可以在后台看不见的地方(但还是在同一个进程里)创建一个叫Service 的东西,它能够在后面静悄悄地执行类似下载的任务,也能够热热闹闹地唱起“苍茫的天涯是你的爱...”,但是这种方式呢,我们就只能跟它说,“Service,做这件事吧”,而没办法在它做一半的时候跟它说,“Service,别做这事了,做那一件事吧”(其实也可以,但是每次都要重新创建一个Intent,里面定义我们要做的事情,然后再次调用startService,让它重新再做,但我觉得,这不科学)。

2)bindService。我们也可以通过 bindService的方法来将Activity 跟 Service 绑定在一起,为什么绑定Service了之后就能够随时叫Service做事了呢?因为通过绑定,从Service返回了一个继承于Binder的类给Activity,而通过这个继承类,可以在里面定义一些交互的回调函数,那么Activity就可以通过这些方法来随时告诉Service要做些啥事了,这才叫交互嘛。

那么,音乐播放器肯定是要用后面这种 bindService的方法了啊,因为我们要交互啊。先看一下界面:

 

在列表界面上和歌词界面上有着不同的控制按钮,比如向前向后,模式改变,播放暂停等,所以我们得想想怎么去设计Service。

如何设计Service?

我把 Service 分成三种情况:
1)要响应 Activity 中按钮的控制;
2)Service中自己要控制的逻辑,比如一首歌播放完之后,要自动播放下一首等;
3)要能够主动地去通知Activity。

第一种情况,其实就是我们要在Binder中定义的接口啦,响应列表界面的唱停前后和模式变换。
class NatureBinder extends Binder{
		
		/**
		 * 唱吧,有人想听
		 */
		public void startPlay(int currentMusic, int currentPosition){}
		
		/**
		 * 别唱了
		 */
		public void stopPlay(){}
		/**
		 * 后一首
		 */
		public void toNext(){}
		
		/**
		 * 前一首
		 */
		public void toPrevious(){}
		
		/**
		 * 有人改变模式了,我得把它记下来 
		 */		
		public void changeMode(){}
		
		/**
		 * 告诉别人,你现在到底是顺序播放,还是随机乱弹
		 * MODE_ONE_LOOP = 1;
		 * MODE_ALL_LOOP = 2;
		 * MODE_RANDOM = 3;
		 * MODE_SEQUENCE = 4; 
		 * @return
		 */
		public int getCurrentMode(){}
		
		/**
		 * 告诉调用者,到底有没有在做事。。。
		 * @return
		 */
		public boolean isPlaying(){}
		
		/**
		 * 要告诉调用者,当前播哪首歌了,歌多长啊
		 */
		public void notifyActivity(){}
		
		/**
		 * 有人拖动Seekbar了,要告诉service去改变播放的位置
		 * @param progress
		 */
		public void changeProgress(int progress){}
	}

那么第二种情况,就是servcie本身的逻辑控制了,其实主要的逻辑是当一首歌播放完了,它得自己去判断下一首要播什么,还有没有得播啊,所以我们要实现MediaPlayer的OnCompletionListener方法,在这里,我们要实现下一步该怎么做,继续播呢,还是停下来,要不要通知列表界面,我换歌了。。。

mediaPlayer.setOnCompletionListener(new OnCompletionListener() {			
			@Override
			public void onCompletion(MediaPlayer mp) {
				...
		});
	}

而第三种情况,就是怎么去通知列表界面了。在这里是通过发送广播的方式,而Activity中会注册相应的广播过滤器来接收Service中发送出去的消息,比如歌曲播放的进度,换歌了之类的。下面的代码是告诉前台,我现在播到哪个位置了,你给我更新一下进度条的位置。
private void toUpdateProgress(){
		if(mediaPlayer != null && isPlaying){					
			int progress = mediaPlayer.getCurrentPosition();					
			Intent intent = new Intent();
			intent.setAction(ACTION_UPDATE_PROGRESS);
			intent.putExtra(ACTION_UPDATE_PROGRESS,progress);
			sendBroadcast(intent);
			handler.sendEmptyMessageDelayed(updateProgress, 1000);					
		}
	}
	

而相对应的,我们在Activity中,会接收到这样的广播,从而做相应的更新,当然,也别忘了要注册对应的Action,不然可收不到。代码如下:
private void registerReceiver(){
		progressReceiver = new ProgressReceiver();	
		IntentFilter intentFilter = new IntentFilter();
		intentFilter.addAction(NatureService.ACTION_UPDATE_PROGRESS);
		...
		registerReceiver(progressReceiver, intentFilter);
	}
	//上面是注册广播,下面是接收广播,最后别忘了,要注销广播
	...

class ProgressReceiver extends BroadcastReceiver{

		@Override
		public void onReceive(Context context, Intent intent) {
			String action = intent.getAction();
			if(NatureService.ACTION_UPDATE_PROGRESS.equals(action)){
				int progress = intent.getIntExtra(NatureService.ACTION_UPDATE_PROGRESS, 0);
				if(progress > 0){
					currentPosition = progress; // Remember the current position
					pbDuration.setProgress(progress / 1000);
				}
			...
		}
		
	}

既然已经把Service 该干什么都想好了,那么很显然下一步,就是来调用Service了嘛。

Service该怎么用?

废话!当然是在Activity中调用了。没错,就是这样,在Activity中我们通过BindService来获得一个Binder,然后就可以通过Binder来跟Service眉来眼去地交流了。
	private NatureBinder natureBinder;	
	
	private ServiceConnection serviceConnection = new ServiceConnection() {
		
		@Override
		public void onServiceDisconnected(ComponentName name) {
			
		}
		
		@Override
		public void onServiceConnected(ComponentName name, IBinder service) {
			natureBinder = (NatureBinder) service;			
		}
	};
	
	private void connectToNatureService(){		
		Intent intent = new Intent(MainActivity.this, NatureService.class);				
		bindService(intent, serviceConnection, BIND_AUTO_CREATE);				
	}
	

当然,也是有几步要走的:
1)创建一个ServiceConnection 对象,在其onServiceConnected方法中返回我们的Binder。 
2)就是调用bindService了,将serviceConnection作为参数传进去。
就是这么简单,接下来,就可以拿binder来做事了。比如
播放:
natureBinder.startPlay(currentMusic,currentPosition);
暂停:
natureBinder.stopPlay();
下一首:
natureBinder.toNext();

是的,就是这样。 差点忘了,请点击源码下载

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。