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() {@Overridepublic 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{@Overridepublic 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 positionpbDuration.setProgress(progress / 1000);}...}}

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

Service该怎么用?

废话!当然是在Activity中调用了。没错,就是这样,在Activity中我们通过BindService来获得一个Binder,然后就可以通过Binder来跟Service眉来眼去地交流了。
private NatureBinder natureBinder;private ServiceConnection serviceConnection = new ServiceConnection() {@Overridepublic void onServiceDisconnected(ComponentName name) {}@Overridepublic 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();

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

更多相关文章

  1. Android(安卓)Gallery3D源码分析(一)
  2. Android中px和dip的区别
  3. Android(安卓)中音频视频开发
  4. Android4开发入门经典 之 第十部分:多媒体
  5. Android(安卓)学习之《第一行代码》第二版 笔记(二十)播放多媒体文
  6. Android(安卓)跳转权限设置界面的终极适配(适配各大定制 ROM)
  7. 自定义BaseActivity
  8. Android上定义播放器控件UniversalVideoView
  9. 使用Android系统自带的应用统计

随机推荐

  1. Test
  2. MVPArch - Android(安卓)MVP 快速开发框
  3. Android(安卓)Debug Bridge 技术实现原理
  4. Android(安卓)Jetpack 使用入门
  5. android 颜色 获取
  6. android sqlcipher 速度太慢,正确使用sql
  7. 数据短信接收
  8. Android字体
  9. Android(安卓)MapView 申请apiKey
  10. android:windowSoftInputMode属性使用