Android实战 - 音心播放器 (Music Service 实现)

来源:互联网 发布:动漫人设用什么软件 编辑:程序博客网 时间:2024/05/16 09:42

1.背景

   音乐的播放,为了实现在后台播放,将在Service 中进行音乐的基本控制,所以 MediaPlay 将在Service 中实现。

在这里使用了,简单的 startService 方式,非 Ibind 方式操作服务,故在关闭Service 上还有些bug , 但并不影响使用;

   Service 学习参考资料 : http://www.android-doc.com/guide/components/services.html

   Service 生命周期 : http://blog.csdn.net/LABLENET/article/details/48073093

   在这个播放器中,为了播放音乐方便,故在应用启动后,当数据加载成功就启动了MusicService 服务。后台服务本身是不可见的,但是在这个为了使其可见就使用了通知(MusicNotification )来人性话,显示服务当前的状态和当前播放音乐的信息,通知下篇实现,这里的主角是Service

  MusicService 服务 :

                                                             


2.Service 实现

    (1)实现MusicService 

              如果直接看源码的时候,十分头疼这些是什么东西,我在这个简单的说明的一下 :

              MusicService 实现的功能是对音乐的基本控制:

                    1.应用启动  (随着应用的启动而启动) 就启动 

                    2.状态栏显示 : notification 

                    3.注册 : bordcastReceiver 

                    4.请求第1首歌 : 更新状态栏 

                    5.实现上一曲,下一曲,播放,暂停控制

                    6.初始化 MusicActivity 内容数据  (这个是歌词/进度条显示页面)

       

       MusicService 源码 : 使用了斜杠进行了分类,应该是可以理解的,boradcastReceiver 的内容将在后面说明。

package cn.labelnet.framework;import java.io.IOException;import java.io.Serializable;import java.util.List;import cn.labelnet.model.MusicModel;import android.app.NotificationManager;import android.app.Service;import android.content.BroadcastReceiver;import android.content.Context;import android.content.Intent;import android.content.IntentFilter;import android.media.MediaPlayer;import android.media.MediaPlayer.OnCompletionListener;import android.media.MediaPlayer.OnErrorListener;import android.media.MediaPlayer.OnPreparedListener;import android.net.Uri;import android.os.IBinder;import android.widget.MediaController.MediaPlayerControl;import android.widget.Toast;public class MusicService extends Service implements OnPreparedListener,OnCompletionListener, OnErrorListener {/** * MusicService 音乐播放控制 : 随着应用的启动而启动 基本步揍 : 1.应用启动 : 就启动 2.状态栏显示 : * notification 3.注册 : bordcastReceiver 4.请求第1首歌 : 更新状态栏 5.实现上一曲,下一曲,播放,暂停控制 */// 常量private final String MUSIC_INTENT_KEY = "musics";private final int MUSIC_INTENT_FLAG = 20001;private final int MAIN_MUSIC_INTENT_FLAG = 20017;// 音乐列表private List<MusicModel> musics = null;private int mmSize = 0;// 通知栏private MusicNotification musicNotifi = null;private MusicModel mm = null;// MediaPlayprivate MediaPlayer mp = null;private int currentTime = 0;// Music广播接收private MusicBroadCast musicBroadCast = null;// MainActivity 来的 Actionprivate final String MAIN_ACTIVIY_ACTION = "mainActivity.To.MusicService";// 来自通知栏的Actionprivate final String MUSIC_NOTIFICATION_ACTION_PLAY = "musicnotificaion.To.PLAY";private final String MUSIC_NOTIFICATION_ACTION_NEXT = "musicnotificaion.To.NEXT";private final String MUSIC_NOTIFICATION_ACTION_CLOSE = "musicnotificaion.To.CLOSE";private final String MUSIC_NOTIFICAION_INTENT_KEY = "notify.music";// MusicService 来的 Actionprivate final String MUSIC_ACTIVITY_SERVICE_ACTION = "activity.to.musicservice";private final String MUSIC_ACTIVITY_SERVICE_KEY = "musictype";private final int MUSIC_ACTIVITY_SERVICE_REQUEST = 40001;// 给MusicActivity 的 Actionprivate final String MUSIC_SERVICE_RECEIVER_ACTION = "service.to.musicactivity";private Intent mActivityIntent = null;private final String MUSIC_SERVICE_TO_ACTIVITY_MODEL = "model";private final String MUSIC_SERVICE_TO_ACTIVITY_ISPLAY = "isplay";private final String MUSIC_SERVICE_TO_ACTIVITY_NOWTIME = "nowtime";// 响应码 : 41001 没数据 , 41002 : 有数据private final String MUSIC_SERVICE_TOACTIVITY_CODE = "mpcode";// Intent keysprivate final String MAIN_MUSIC_INTENT_KEY = "mIntent";@Overridepublic void onCreate() {// 初始化MusicActivity 的 Intent ,给 MusicActivity 发送广播 ,修改音乐播放界面mActivityIntent = new Intent();mActivityIntent.setAction(MUSIC_SERVICE_RECEIVER_ACTION);// 初始化通知栏musicNotifi = MusicNotification.getMusicNotification();musicNotifi.setContext(getApplicationContext());musicNotifi.setManager((NotificationManager) getSystemService(NOTIFICATION_SERVICE));musicNotifi.onCreateMusicNotifi();// 初始化MediaPlay : 设置监听事件mp = new MediaPlayer();mp.setOnPreparedListener(this);mp.setOnCompletionListener(this);mp.setOnErrorListener(this);// 注册广播musicBroadCast = new MusicBroadCast();IntentFilter filter = new IntentFilter();filter.addAction(MAIN_ACTIVIY_ACTION);filter.addAction(MUSIC_ACTIVITY_SERVICE_ACTION);filter.addAction(MUSIC_NOTIFICATION_ACTION_PLAY);filter.addAction(MUSIC_NOTIFICATION_ACTION_NEXT);filter.addAction(MUSIC_NOTIFICATION_ACTION_CLOSE);registerReceiver(musicBroadCast, filter);super.onCreate();}@Overridepublic IBinder onBind(Intent intent) {return null;}@SuppressWarnings("unchecked")@Overridepublic int onStartCommand(Intent intent, int flags, int startId) {try{musics = (List<MusicModel>) intent.getSerializableExtra(MUSIC_INTENT_KEY);}catch(Exception e){}if (musics != null) {mmSize = musics.size();}// showToast("1." + musics.get(1).getSongname());return super.onStartCommand(intent, flags, startId);}@Overridepublic void onDestroy() {if (mp != null) {mp.stop();mp.release();mp = null;musics = null;}// 取消注册的广播unregisterReceiver(musicBroadCast);}// //////////////////////////////Music Util//////////////////////// Toastprivate void showToast(String msg) {Toast.makeText(getApplicationContext(), msg, Toast.LENGTH_SHORT).show();}// 音乐播放private void play(String musicUrl) {mp.reset();try {mp.setDataSource(getApplicationContext(), Uri.parse(musicUrl));mp.prepareAsync();} catch (IOException e) {showToast("网络错误,播放失败");}musicNotifi.onUpdataMusicNotifi(mm, true);}// 音乐暂停private void pause() {if (mp.isPlaying()) {currentTime = mp.getCurrentPosition();mp.pause();}musicNotifi.onUpdataMusicNotifi(mm, false);}// 音乐继续播放private void resume() {mp.start();if (currentTime > 0) {mp.seekTo(currentTime);}musicNotifi.onUpdataMusicNotifi(mm, true);}// 音乐停止private void stop() {mp.stop();try {mp.prepare();} catch (IOException e) {showToast("音乐停止异常");}musicNotifi.onUpdataMusicNotifi(mm, false);}// //////////////////////////////Music MediaPlayListener////////////@Overridepublic boolean onError(MediaPlayer mp, int what, int extra) {// 出错的时候return false;}@Overridepublic void onCompletion(MediaPlayer mp) {// 播放完毕的时候//showToast("播放完毕,准备播放下一首!");currentTime = 0;// 改变通知栏musicNotifi.onUpdataMusicNotifi(mm, false);//改变MusicActivitysendModelToMusicActivity();}@Overridepublic void onPrepared(MediaPlayer mp) {// 准备加载的时候resume();sendModelToMusicActivity();}// ////////////////////////////其他工具方法///////////////////////////////////** * 发送Model给MusicActivity */private void sendModelToMusicActivity() {if (mm != null) {// 正在播放的歌曲实体if(mm.getSeconds()==0){mm.setSeconds(mp.getDuration()/1000);}mActivityIntent.putExtra(MUSIC_SERVICE_TOACTIVITY_CODE, 41002);mActivityIntent.putExtra(MUSIC_SERVICE_TO_ACTIVITY_ISPLAY,mp.isPlaying());mActivityIntent.putExtra(MUSIC_SERVICE_TO_ACTIVITY_NOWTIME,mp.getDuration() - mp.getCurrentPosition());mActivityIntent.putExtra(MUSIC_SERVICE_TO_ACTIVITY_MODEL,(Serializable) mm);} else {// 默认发送第一首歌信息mm = musics.get(0);mActivityIntent.putExtra(MUSIC_SERVICE_TOACTIVITY_CODE, 41001);mActivityIntent.putExtra(MUSIC_SERVICE_TO_ACTIVITY_ISPLAY,mp.isPlaying());mActivityIntent.putExtra(MUSIC_SERVICE_TO_ACTIVITY_MODEL,(Serializable) mm);}sendBroadcast(mActivityIntent);}// //////////////////////////////Music BroadCastReceiver////////////// 接收广播private class MusicBroadCast extends BroadcastReceiver {private int flag = 0, position = -1, kzhi = 0, musictype = 0;@Overridepublic void onReceive(Context context, Intent intent) {// 2.MainActivity 控制flag = intent.getFlags();mainToService(intent);// 3.MusicNotification控制kzhi = intent.getIntExtra("type", -1);if (kzhi > 0) {musicNotificationService(kzhi);}// 4.MusicActivity 来的控制musictype = intent.getIntExtra(MUSIC_ACTIVITY_SERVICE_KEY, 0);if (musictype > 0) {musicActivityService(musictype);}}/** * 来自 MusicActivity 的控制 *  * @param musictype2 */private void musicActivityService(int musictype2) {//showToast("musicActivityService 执行了 musictype2 :" + musictype2);switch (musictype2) {case 40001:sendModelToMusicActivity();break;case 40002://播放与暂停playSong(); break;case 40003:                //下一曲                  nextSong();break;case 40004:               //上一曲preSong();break;}}/** * musicNotification 来的控制 *  * @param intent */private void musicNotificationService(int k) {switch (k) {case 30001:// 播放playSong();break;case 30002:// 下一首nextSong();break;case 30003:// 关闭通知栏musicNotifi.onCancelMusicNotifi();// 停止音乐stop();break;}}/** * 播放 */private void playSong() {if (mp.isPlaying()) {pause();} else {if (currentTime > 0) {resume();} else {if (mm != null) {play(mm.getUrl());}}}sendModelToMusicActivity();}/** * 下一曲 */private void nextSong() {currentTime=0;if(position<0){position=0;}if (mmSize > 0) {position++;if (position < mmSize) {// 不超过长度mm = musics.get(position);play(mm.getUrl());} else {// 超过长度 播放第一首mm = musics.get(0);play(mm.getUrl());}}}/** * 上一曲 */private void preSong(){currentTime=0;if(position<0){position=0;}if (mmSize > 0) {position--;if (position>=0) {//不小于0mm = musics.get(position);play(mm.getUrl());} else {// 超过长度 播放第一首,小于0 ,播放第一首mm = musics.get(0);play(mm.getUrl());}}}/** * MainActivity来的数据 *  * @param intent */private void mainToService(Intent intent) {if (MAIN_MUSIC_INTENT_FLAG == flag) {// 来自MainActivity 的操作position = intent.getIntExtra(MAIN_MUSIC_INTENT_KEY, -1);// showToast("3.来自MainActivity 问候 : " + position);if (position > -1) {// 播放if (musics != null) {mm = musics.get(position);} else {//showToast("4.MUSICS IS NULL");}if (mm != null) {/** * 1.播放音乐 2.更新状态栏 3.如果进度条运行的话,通知改变 */play(mm.getUrl());} else {//showToast("5.musics 数据去哪里了!");}} else {//showToast("6.这怎么可能发生呢?!");}} else {//showToast("不是MainActivity 来的数据");}}}}

       (2)注册Service 

                  在AndroidMainfest.xml中注册 

    <service android:name="cn.labelnet.framework.MusicService" >        </service>

      (3)启动服务

             这里使用了 Serializable序列化进行了数据传递,不建议使用这个,效率低,可以使用Parcleable,效率高;

             参考文章 : 

Android - Parcelable接口用法 和 与 Serializable 的区别

@Overridepublic void getMusicModelList(List<MusicModel> models) {// 初始化 Service : 开启MUSIC服务Intent intent = new Intent(MainActivity.this, MusicService.class);intent.putExtra(MUSIC_INTENT_KEY, (Serializable) models);intent.addFlags(MUSIC_INTENT_FLAG);startService(intent);//关闭进度条swiperefresh_wei.setRefreshing(false);isRefresh=false;}


3.播放器控制

          播放器控制主要实现是实现 play() , pause() , resume(),stop() 四个方法,进行播放,暂停,重新播放控制。同时实现onPrepaed() , onCompletion() , onError() 三个监听,实现对播放器的控制,最基本的操作就在此了。后面的通知栏控制,歌词/进度条页面控制 均是使用 这几个方法进行控制实现。

<span style="font-family:Comic Sans MS;font-size:18px;">// 音乐播放private void play(String musicUrl) {mp.reset();try {mp.setDataSource(getApplicationContext(), Uri.parse(musicUrl));mp.prepareAsync();} catch (IOException e) {showToast("网络错误,播放失败");}musicNotifi.onUpdataMusicNotifi(mm, true);}// 音乐暂停private void pause() {if (mp.isPlaying()) {currentTime = mp.getCurrentPosition();mp.pause();}musicNotifi.onUpdataMusicNotifi(mm, false);}// 音乐继续播放private void resume() {mp.start();if (currentTime > 0) {mp.seekTo(currentTime);}musicNotifi.onUpdataMusicNotifi(mm, true);}// 音乐停止private void stop() {mp.stop();try {mp.prepare();} catch (IOException e) {showToast("音乐停止异常");}musicNotifi.onUpdataMusicNotifi(mm, false);}// //////////////////////////////Music MediaPlayListener////////////@Overridepublic boolean onError(MediaPlayer mp, int what, int extra) {// 出错的时候return false;}@Overridepublic void onCompletion(MediaPlayer mp) {// 播放完毕的时候//showToast("播放完毕,准备播放下一首!");currentTime = 0;// 改变通知栏musicNotifi.onUpdataMusicNotifi(mm, false);//改变MusicActivitysendModelToMusicActivity();}@Overridepublic void onPrepared(MediaPlayer mp) {// 准备加载的时候resume();sendModelToMusicActivity();}</span>

4.总结

   MusicService 的实现是整个播放器的核心,所以进步的音乐控制均在此实现,算是播放器的心脏。

   下篇将实现通知栏实现- MusicSerivce 的脸;





0 0
原创粉丝点击