上一篇写了载入歌曲列表,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"; @Override
public void onCreate() {
// TODO Auto-generated method stub
if (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);
} @Override
public void onDestroy() {
// TODO Auto-generated method stub
if (mp != null) {
stop();
mp.release();
} if (handler != null) {
handler.removeMessages(1);
handler = null;
} if(notificationManager!=null){
notificationManager.cancel(notiID);
}
} @Override
public int onStartCommand(Intent intent, int flags, int startId) {
// TODO Auto-generated method stub Song 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 block
e.printStackTrace();
} catch (SecurityException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalStateException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.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() { @Override
public void onPrepared(MediaPlayer mp) {
// TODO Auto-generated method stub
handler.sendEmptyMessage(1);
}
});
}catch (Exception e) {
// TODO Auto-generated catch block
e.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() { @Override
public void handleMessage(Message msg) {
// TODO Auto-generated method stub
if (msg.what == 1) {
currentTime = mp.getCurrentPosition(); Log.i("currentTime", currentTime+"");
intent.putExtra("currentTime", currentTime);
sendBroadcast(intent);
} handler.sendEmptyMessageDelayed(1, 800);
} };
} @Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
return null;
} @Override
public void onCompletion(MediaPlayer mp) {
// TODO Auto-generated method stub mp.reset(); Intent intent=new Intent();
intent.setAction(MUSIC_NEXT);
sendBroadcast(intent);
} }
下一篇智能匹配本地歌词:http://blog.csdn.net/huweigoodboy/article/details/39862773
android音乐播放器开发 SweetMusicPlayer 播放本地音乐的更多相关文章
-
android音乐播放器开发 SweetMusicPlayer 智能匹配本地歌词
上一篇写了使用MediaPlayer播放音乐,http://blog.csdn.net/huweigoodboy/article/details/39861539. 代码地址:https://gith ...
-
android音乐播放器开发 SweetMusicPlayer 实现思路
一,实现效果 眼下还不是特别完好,主要有下面几个功能, 1,载入歌曲列表(实现a-z字母检索) 2,播放本地音乐 3.智能匹配本地歌词 4.智能载入在线歌词(事实上不算智能.发现歌词迷api提供的歌词 ...
-
android音乐播放器开发 SweetMusicPlayer 载入歌曲列表
上一篇写了播放器的总体实现思路,http://blog.csdn.net/huweigoodboy/article/details/39855653,如今来总结下载入歌曲列表. 代码地址:https: ...
-
android音乐播放器开发 SweetMusicPlayer
智能负载直插式歌词
在一份书面的使用MediaPlayer播放音乐, http://blog.csdn.net/huweigoodboy/article/details/39862773.假设没有本地歌词怎么办?如今来将 ...
-
android音乐播放器开发 SweetMusicPlayer 摇一摇换歌
上一篇写了怎样在线匹配歌词,http://blog.csdn.net/huweigoodboy/article/details/39878063,如今来讲讲摇一摇功能开发. 相同用了一个Service ...
-
android音乐播放器开发教程
android音乐播放器开发教程 Android扫描sd卡和系统文件 Android 关于录音文件的编解码 实现米聊 微信一类的录音上传的功能 android操作sdcard中的多媒体文件——音乐列表 ...
-
仿酷狗音乐播放器开发日志十九——CTreeNodeUI的bug修复二(附源码)
转载请说明原出处,谢谢 今天本来打算把仿酷狗播放列表的子控件拖动插入功能做一下,但是仔细使用播放列表控件时发现了几个逻辑错误,由于我的播放 列表控件是基于CTreeViewUI和CTreeNodeUI ...
-
使用Vitamio打造自己的Android万能播放器(4)——本地播放(快捷搜索、数据存储)
前言 关键字:Vitamio.VPlayer.Android播放器.Android影音.Android开源播放器 本章节把Android万能播放器本地播放的主要功能(缓存播放列表和A-Z快速查询功能) ...
-
基于VLC的播放器开发
VLC的C++封装 因为工作需要,研究了一段时间的播放器开发,如果从头开始做,可以学习下FFmpeg(http://www.ffmpeg.org/),很多播放器都是基于FFmpeg开发的,但是这样工作 ...
随机推荐
-
Python高手之路【一】初识python
Python简介 1:Python的创始人 Python (英国发音:/ˈpaɪθən/ 美国发音:/ˈpaɪθɑːn/), 是一种解释型.面向对象.动态数据类型的高级程序设计语言,由荷兰人Guido ...
-
SQL代码创建表例子
create table class ( code ) primary Key, name ) ); create table student ( code ) primary Key, name ) ...
-
zookeeper源码学习一——zookeeper启动
最近正在研究zookeeper,一些心得记录一下,如有错误,还请大神指正. zookeeper下载地址:http://zookeeper.apache.org/releases.html,百度一下就能 ...
-
WeifenLuo.WinFormsUI.Docking";的使用 z
在伍华聪的博客中,看到布局控件"WeifenLuo.WinFormsUI.Docking",发现的确是一个非常棒的开源控件,用过的人都深有体会,该控件之强大.美观.不亚于商业控件. ...
-
ACM题目推荐(刘汝佳书上出现的一些题目)[非原创]
原地址:http://blog.csdn.net/hncqp/article/details/1758337 推荐一些题目,希望对参与ICPC竞赛的同学有所帮助. POJ上一些题目在http://16 ...
-
php 常用代码段
1.写文件 $fp = fopen("jsapi_ticket.json", "w+"); fwrite($fp, $str); fclose($fp); 2. ...
-
初识Djiango
老师的博客:点我 内容主要是看老师的博客 下面是自己的写的某些自己当时不太懂的. 关于Django的版本的问题 Django官网下载页面 在官网上显示lts的是表示支持长期版本.所以最好下载1.11版 ...
-
关于 mysql2 -v '0.3.21'(CentOS7.3)
个人由于没有安装mysql而是装的MariaDB,所以网上说安装mysql,故没有采用,经查阅资料后,详细情况如下: Gem时报错: [root@localhost ~]# gem install m ...
-
board_key.h/board_key.c
/******************************************************************************* Filename: board_key ...
-
Java 1.ExecutorService四种线程池的例子与说明
1.new Thread的弊端 执行一个异步任务你还只是如下new Thread吗? new Thread(new Runnable() { @Override public void run() { ...