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 的脸;
- Android实战 - 音心播放器 (Music Service 实现)
- Android实战 - 音心播放器 (优化Service退出,按两下退出应用实现)
- android播放器(music player)源码分析1-Service,Binder,ServiceConnection
- android播放器(music player)源码分析1-Service,Binder,ServiceConnection
- Android实战 - 音心播放器(MusicActivity - 歌词实现)
- Android实战 - 音心播放器 (通知实现音乐的播放/暂停/下一曲控制)
- Android实战 - 音心播放器 (MusicActivity-音乐播放页面界面实现)
- Android实现音乐播放 Music 详解
- android源码解析------Music 音乐播放器
- 基于service服务后台运行的music播放器
- Android实战 - 音心播放器 (MusciActivity-专辑图片获得,基本控制实现)
- Android实战 - 音心播放器 (MusicActivity - 倒计时 ,进度条实现)
- Android实战 - 音心播放器 (MusicListActivity - 分类信息界面实现)
- android音乐播放器实现(Service+BroadcastReceiver+Notification)
- Android 用service实现视频播放器
- Android音乐播放器 -- MediaPlayer Service实现
- Android实战 - 音心播放器 (MusicListActivity - 音乐播放和MainActivity的一个问题)
- Android中music播放器源码要点详解【安卓music源码进化一】
- 斯坦福机器学习2:监督学习应用
- 按下按钮圆圈改变颜色
- [Coursera]算法基础_Week9_考试_Q4
- button作为asp.net服务器控件时在IE提交两次
- HTML兼容性问题
- Android实战 - 音心播放器 (Music Service 实现)
- 实战c++中的vector系列--copy set to vector(别混淆了reserve和resize)
- LR11录制回放出现中文乱码以及录制时一直跳到360浏览器的解决方法
- 常见错误8-搭建hexo,本地server成功,部署到github上之后不能显示主题样式
- hdu1176 免费馅饼
- Ant(GG)
- 因为PPBC的防盗链,尝试用vba的对象来解决,顺便复习一下。。。
- NGUI 背包暂时完成
- 对于nginx一些配置的建议值