代码地址:https://github.com/huweigoodboy/SweetMusicPlayer

上一篇写了加载歌曲列表,http://blog.csdn.net/huweigoodboy/article/details/39856411,现在来总结下播放本地音乐。

一,MediaPlayer

首先来看看MediaPlayer的生命周期:

Idle 状态:当使用new()方法创建一个MediaPlayer对象或者调用了其reset()方法时,该MediaPlayer对象处于idle状态。这两种方法的一个重要差别就是:如果在这个状态下调用了getDuration()等方法(相当于调用时机不正确),通过reset()方法进入idle状态的话会触发OnErrorListener.onError(),并且MediaPlayer会进入Error状态;如果是新创建的MediaPlayer对象,则并不会触发onError(),也不会进入Error状态。

 

End 状态:通过release()方法可以进入End状态,只要MediaPlayer对象不再被使用,就应当尽快将其通过release()方法释放掉,以释放相关的软硬件组件资源,这其中有些资源是只有一份的(相当于临界资源)。如果MediaPlayer对象进入了End状态,则不会在进入任何其他状态了。

 

Initialized 状态:这个状态比较简单,MediaPlayer调用setDataSource()方法就进入Initialized状态,表示此时要播放的文件已经设置好了。

 

Prepared 状态:初始化完成之后还需要通过调用prepare()或prepareAsync()方法,这两个方法一个是同步的一个是异步的,只有进入Prepared状态,才表明MediaPlayer到目前为止都没有错误,可以进行文件播放。

 

Preparing 状态:这个状态比较好理解,主要是和prepareAsync()配合,如果异步准备完成,会触发OnPreparedListener.onPrepared(),进而进入Prepared状态。

 

Started 状态:显然,MediaPlayer一旦准备好,就可以调用start()方法,这样MediaPlayer就处于Started状态,这表明MediaPlayer正在播放文件过程中。可以使用isPlaying()测试MediaPlayer是否处于了Started状态。如果播放完毕,而又设置了循环播放,则MediaPlayer仍然会处于Started状态,类似的,如果在该状态下MediaPlayer调用了seekTo()或者start()方法均可以让MediaPlayer停留在Started状态。

 

Paused 状态:Started状态下MediaPlayer调用pause()方法可以暂停MediaPlayer,从而进入Paused状态,MediaPlayer暂停后再次调用start()则可以继续MediaPlayer的播放,转到Started状态,暂停状态时可以调用seekTo()方法,这是不会改变状态的。

 

Stop 状态:Started或者Paused状态下均可调用stop()停止MediaPlayer,而处于Stop状态的MediaPlayer要想重新播放,需要通过prepareAsync()和prepare()回到先前的Prepared状态重新开始才可以。

 

PlaybackCompleted状态:文件正常播放完毕,而又没有设置循环播放的话就进入该状态,并会触发OnCompletionListener的onCompletion()方法。此时可以调用start()方法重新从头播放文件,也可以stop()停止MediaPlayer,或者也可以seekTo()来重新定位播放位置。

Error状态:如果由于某种原因MediaPlayer出现了错误,会触发OnErrorListener.onError()事件,此时MediaPlayer即进入Error状态,及时捕捉并妥善处理这些错误是很重要的,可以帮助我们及时释放相关的软硬件资源,也可以改善用户体验。通过setOnErrorListener(android.media.MediaPlayer.OnErrorListener)可以设置该监听器。如果MediaPlayer进入了Error状态,可以通过调用reset()来恢复,使得MediaPlayer重新返回到Idle状态。

说明:

1,获取MediaPlayer的实例:

1)通过new方式:MediaPlayer mp=new MediaPlayer();

2) 通过create方式:MediaPlayer mp=MediaPlaer.create(this,R.raw.music);//此时就不需要再次setDataSource()了

2,设置播放资源

1)播放sd卡上资源

mp.setDataSource("/sdcard/music.mp3");

2)播放raw目录下的资源

MediaPlayer mp=MediaPlaer.create(this,R.raw.music);

3)网络媒体上的资源

mp.setDataSource("http://music.com/music.mp3");

3,控制方法

prepare()和prepareAsync()  提供了同步和异步两种方式设置播放器进入prepare状态,需要注意的是,如果MediaPlayer实例是由create方法创建的,那么第一次启动播放前不需要再调用prepare()了,因为create方法里已经调用过了。

start()是真正启动文件播放的方法,

pause()和stop()比较简单,起到暂停和停止播放的作用,

seekTo()是定位方法,可以让播放器从指定的位置开始播放,需要注意的是该方法是个异步方法,也就是说该方法返回时并不意味着定位完成,尤其是播放的网络文件,真正定位完成时会触发OnSeekComplete.onSeekComplete(),如果需要是可以调用setOnSeekCompleteListener(OnSeekCompleteListener)设置监听器来处理的。

release()可以释放播放器占用的资源,一旦确定不再使用播放器时应当尽早调用它释放资源。

reset()可以使播放器从Error状态中恢复过来,重新会到Idle状态。

4)设置播放器的监听器:

MediaPlayer提供了一些设置不同监听器的方法来更好地对播放器的工作状态进行监听,以期及时处理各种情况,

如: setOnCompletionListener(MediaPlayer.OnCompletionListener listener)、

setOnErrorListener(MediaPlayer.OnErrorListener listener)等,设置播放器时需要考虑到播放器可能出现的情况设置好监听和处理逻辑,以保持播放器的健壮性。

上面部分多为引用,能够更好地理解MediaPlayer。

二,控制播放的service

为什么不用activity呢?如果切到后台,activity就会被销毁,播放就会出现各种问题。

这里设置各种状态,如PLAY,PAUSE,STOP,PROGRESS_CHANGE,不同的状态对应不同的操作。

在服务启动后,应该去获取当前播放的歌曲,然后去new MediaPlayer()和设置setDateSource();

1,PLAY操作:

1)mp.prepare();

2)当mp准备好后,向ui发送广播,通知歌词界面,bottomactionbar更新信息。

3)mp.start();

2.PAUSE

1)移除广播

2)mp.pasue()

3,STOP

1)移除广播

2)mp.stop()

3)mp.reset()

4,PROGRESS_CHANGE

发送进度变更的广播

具体代码:

package com.huwei.sweetmusicplayer.services;import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.URL;import com.huwei.sweetmusicplayer.R;
import com.huwei.sweetmusicplayer.datamanager.MusicManager;
import com.huwei.sweetmusicplayer.enums.MusicState;import com.huwei.sweetmusicplayer.models.Song;
import com.huwei.sweetmusicplayer.ui.widgets.NotificationView;import com.slidelib.MainActivity;import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Intent;
import android.media.MediaPlayer;
import android.media.MediaPlayer.OnCompletionListener;
import android.media.MediaPlayer.OnPreparedListener;
import android.net.Uri;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.provider.MediaStore;
import android.util.Log;
import android.widget.RemoteViews;public class LocalMusicService extends Service implements OnCompletionListener{private static final String TAG="LocalMusicService";private MediaPlayer mp; // mediaPlayer对象private int currentTime;private int duration;private int id;private Uri uri;private Handler handler;NotificationManager notificationManager;private final int notiID=987654321;private static final String MUSIC_CURRENT = "com.music.currentTime";private static final String MUSIC_DURATION = "com.music.duration";private static final String MUSIC_NEXT = "com.music.next";private static final String MUSIC_UPDATE = "com.music.update";@Overridepublic void onCreate() {// TODO Auto-generated method stubif (mp != null) {mp.reset();mp.release();}mp = new MediaPlayer();//设置结束后的监听mp.setOnCompletionListener(this);}void showMusicPlayerNotification(String tickerText, int id,  int resId, int photoId, String title, String artist){notificationManager=(NotificationManager) getSystemService(NOTIFICATION_SERVICE);Notification notification=new Notification(resId, title, System.currentTimeMillis());notification.flags|=Notification.FLAG_NO_CLEAR ;notification.flags|=Notification.FLAG_INSISTENT ;RemoteViews reViews=new RemoteViews(getPackageName(),R.layout.notification_play);reViews.setTextViewText(R.id.title, title);reViews.setTextViewText(R.id.text, artist);reViews.setImageViewResource(R.id.imageview_notification_play, photoId);Intent intent=new Intent(this,MainActivity.class);intent.addCategory(Intent.CATEGORY_LAUNCHER);intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);PendingIntent pendingIntent=PendingIntent.getActivity(getBaseContext(), 0, intent, 0);Log.i(TAG, "pendingIntent:"+pendingIntent);notification.contentView=reViews;//notification.bigContentView=reViews;notification.contentIntent=pendingIntent;notificationManager.notify(id, notification);}@Overridepublic void onDestroy() {// TODO Auto-generated method stubif (mp != null) {stop();mp.release();}if (handler != null) {handler.removeMessages(1);handler = null;}if(notificationManager!=null){notificationManager.cancel(notiID);}}@Overridepublic int onStartCommand(Intent intent, int flags, int startId) {// TODO Auto-generated method stubSong song=(Song) intent.getSerializableExtra("song");if(null!=song&&song.getId()!=-1){id=song.getId();uri=Uri.withAppendedPath(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, ""+id);Log.i("playUri", uri.toString());try {//mp.reset();mp.setDataSource(getBaseContext(), uri);} catch (IllegalArgumentException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (SecurityException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (IllegalStateException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}//显示通知栏showMusicPlayerNotification(getResources().getString(R.string.app_name), notiID,  R.drawable.sweet, R.drawable.smiley_24, song.getTitle(), song.getArtist());  }int op=intent.getIntExtra("op", -1);if(op!=-1){MusicState ms=MusicState.values()[op];Log.i("MusicState", op+"");switch(ms){case  PLAYING:play();break;case PAUSE:pause();break;case STOP:stop();break;case PROGRESS_CHANGE:int progress=intent.getExtras().getInt("progress");mp.seekTo(progress);break;}}return super.onStartCommand(intent, flags, startId);}// 播放音乐public void play() {setup();init();if(mp!=null){mp.start();}}// 暂停音乐public void pause() {//移除广播handler.removeMessages(1);if(mp!=null){mp.pause();}}// 停止音乐public void stop() {if(mp!=null){mp.stop();mp.reset();}//if(handler!=null) handler.removeMessages(1);}// 准备工作public void setup() {Intent intent = new Intent();intent.setAction(MUSIC_DURATION);try {
//          if (!mp.isPlaying()) {
//              mp.prepare();
//          } mp.prepare();//mp.setWakeMode(getBaseContext(), PowerManager.PARTIAL_WAKE_LOCK);mp.setScreenOnWhilePlaying(true);mp.setOnPreparedListener(new OnPreparedListener() {@Overridepublic void onPrepared(MediaPlayer mp) {// TODO Auto-generated method stubhandler.sendEmptyMessage(1);}});}catch (Exception e) {// TODO Auto-generated catch blocke.printStackTrace();}duration=mp.getDuration();intent.putExtra("duration", duration);sendBroadcast(intent);}// 初始化服务public void init() {final Intent intent = new Intent();intent.setAction(MUSIC_CURRENT);handler = new Handler() {@Overridepublic void handleMessage(Message msg) {// TODO Auto-generated method stubif (msg.what == 1) {currentTime = mp.getCurrentPosition();Log.i("currentTime", currentTime+"");intent.putExtra("currentTime", currentTime);sendBroadcast(intent);}handler.sendEmptyMessageDelayed(1, 800);}};}@Overridepublic IBinder onBind(Intent intent) {// TODO Auto-generated method stubreturn null;}@Overridepublic void onCompletion(MediaPlayer mp) {// TODO Auto-generated method stubmp.reset();Intent intent=new Intent();intent.setAction(MUSIC_NEXT);sendBroadcast(intent);}}

下一篇智能匹配本地歌词:http://blog.csdn.net/huweigoodboy/article/details/39862773

android音乐播放器开发 SweetMusicPlayer 播放本地音乐相关推荐

  1. Android音乐播放器开发(5)—播放界面(播放、暂停、上一首、下一首,顺序播放、随机播放、拖拽进度条…)

    1. 说明 源码已同步到Gitee仓库,Github仓库,觉得还不错的话帮忙点个"star"吧,非常感谢. Android播放器专栏其它文章: 服务端:Android音乐播放器开发 ...

  2. SkeyeWebPlayer.js H5播放器开发之播放器控制栏部分功能的实现(四)

    SkeyeWebPlayer.js H5免费播放器 支持Websocket-RTSP播放; 支持 m3u8(HLS) 播放; 支持 HTTP-FLV/WS-FLV 播放; 支持 HEVC/H265 播 ...

  3. android音乐播放器开发 SweetMusicPlayer 智能匹配本地歌词

    上一篇写了使用MediaPlayer播放音乐,http://blog.csdn.net/huweigoodboy/article/details/39861539. 代码地址:https://gith ...

  4. android音乐播放器开发 SweetMusicPlayer 实现思路

    代码地址:https://github.com/huweigoodboy/SweetMusicPlayer 一,实现效果 目前还不是特别完善,主要有以下几个功能, 1,加载歌曲列表(实现a-z字母检索 ...

  5. android音乐播放器开发 SweetMusicPlayer 载入歌曲列表

    上一篇写了播放器的总体实现思路,http://blog.csdn.net/huweigoodboy/article/details/39855653,如今来总结下载入歌曲列表. 代码地址:https: ...

  6. android音乐播放器开发 SweetMusicPlayer 加载歌曲列表

    上一篇写了播放器的整体实现思路,http://blog.csdn.net/huweigoodboy/article/details/39855653,现在来总结下加载歌曲列表. 代码地址:https: ...

  7. SkeyeWebPlayer.js H5播放器开发之播放器video动态创建(三)

    SkeyeWebPlayer.js H5播放器是由成都视开信息科技开发和维护的一个完善的RTSP.FLV.HLS等多种流媒体协议播放,视频编码支持H.264,H.265,音频支持AAC,支持TCP/U ...

  8. android音乐播放器开发 SweetMusicPlayer 摇一摇换歌

    上一篇写了如何在线匹配歌词,http://blog.csdn.net/huweigoodboy/article/details/39878063,现在来讲讲摇一摇功能开发. 代码地址:https:// ...

  9. html音乐播放器自动切歌,HTML音乐播放——切歌

    $(function(){ $("#next").click(next); }); // 使用JQuery选择标签,则切歌后两首歌一起播放,用JS挺好 var eBar = doc ...

最新文章

  1. 有你认识的么?新鲜出炉!云+社区2020年度优秀讲师TOP作者榜单!
  2. 慢吞吞的pip切换源
  3. node:express:error---填坑之路
  4. 浅析 Dapr 里的云计算设计模式
  5. skyeye linux qt,ARM仿真器SkyEye的安装及使用
  6. android用MP4v2保存视频出现的问题
  7. webpack4入门笔记——loader
  8. html高德地图的使用方法,高德地图的使用方法
  9. 【Unity3D插件】Highlighting System插件分享《物体高亮插件》
  10. pycharm汉化包下载
  11. windows defender卸载_16款仙级软件一定能提高你的Windows舒适度,工作效率翻倍
  12. 用计算机如何打对数,怎样使用科学计算器计算对数?
  13. 八年级英语下册计算机教学总结,初中信息技术教学工作总结
  14. DxO PhotoLab 4 for Mac(RAW图片处理工具)
  15. 跨专业本科毕业小白程序员的入职心得——第一篇
  16. SQL注入原理及防范
  17. java基于ssm的电影院订票选座系统
  18. docusign文档打不开_DocuSign - 用手机签署你的个人文件,完美的无纸化办公就在这里 - Android 应用 - 【最美应用】...
  19. ERP : 库存管理的基本原理
  20. 快速复制备份多个文件,覆盖过重复的文件

热门文章

  1. Python编程之md5加密和sha1加密
  2. How DICK’S moved its software development in-house and aced omnichannel retail
  3. 3.1.2随机梯度下降法
  4. Mysql.索引存储结构演进(面试一次搞定)
  5. WORD中表格的跨页显示
  6. 集成学习中boosting、bagging、随机森林算法的介绍
  7. Eclipse插件TPTP-程序Profile与分析工具详细教程
  8. java 生成证书图片_java生成自定义证书图片1 - 制作证书word模板
  9. 网上贵金属交易怎么操作?网上贵金属交易策略有哪些?
  10. 解决m3u8视频合并问题