上一篇写了载入歌曲列表,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 播放本地音乐的更多相关文章

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

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

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

    一,实现效果 眼下还不是特别完好,主要有下面几个功能, 1,载入歌曲列表(实现a-z字母检索) 2,播放本地音乐 3.智能匹配本地歌词 4.智能载入在线歌词(事实上不算智能.发现歌词迷api提供的歌词 ...

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

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

  4. android音乐播放器开发 SweetMusicPlayer 智能负载直插式歌词

    在一份书面的使用MediaPlayer播放音乐, http://blog.csdn.net/huweigoodboy/article/details/39862773.假设没有本地歌词怎么办?如今来将 ...

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

    上一篇写了怎样在线匹配歌词,http://blog.csdn.net/huweigoodboy/article/details/39878063,如今来讲讲摇一摇功能开发. 相同用了一个Service ...

  6. android音乐播放器开发教程

    android音乐播放器开发教程 Android扫描sd卡和系统文件 Android 关于录音文件的编解码 实现米聊 微信一类的录音上传的功能 android操作sdcard中的多媒体文件——音乐列表 ...

  7. 仿酷狗音乐播放器开发日志十九——CTreeNodeUI的bug修复二(附源码)

    转载请说明原出处,谢谢 今天本来打算把仿酷狗播放列表的子控件拖动插入功能做一下,但是仔细使用播放列表控件时发现了几个逻辑错误,由于我的播放 列表控件是基于CTreeViewUI和CTreeNodeUI ...

  8. 使用Vitamio打造自己的Android万能播放器(4)——本地播放(快捷搜索、数据存储)

    前言 关键字:Vitamio.VPlayer.Android播放器.Android影音.Android开源播放器 本章节把Android万能播放器本地播放的主要功能(缓存播放列表和A-Z快速查询功能) ...

  9. 基于VLC的播放器开发

    VLC的C++封装 因为工作需要,研究了一段时间的播放器开发,如果从头开始做,可以学习下FFmpeg(http://www.ffmpeg.org/),很多播放器都是基于FFmpeg开发的,但是这样工作 ...

随机推荐

  1. javascript之事件

    客户端javascript程序采用了异步事件驱动编程模型. 相关事件的几个概念: 事件类型(event type):用来说明发生什么类型事件的字符串: 事件目标(event target):发生事件的 ...

  2. JNI/NDK开发指南(二)——JVM查找java native方法的规则

    通过第一篇文章,大家明白了调用native方法之前,首先要调用System.loadLibrary接口加载一个实现了native方法的动态库才能正常访问,否则就会抛出java.lang.Unsatis ...

  3. Unreal Engine4 蓝图讲解

    UE4开发群:344602753 Unread Engine4的界面概况: UE4的效果可以说是比较好的,从整体架构上来说,和Unity3d的逻辑架构不太 一样,发现UE4不好上手,但是从理论上考虑, ...

  4. [wikioi]最长严格上升子序列

    http://wikioi.com/problem/1576/ 经典的动态规划.我写了个o(n^2)的DP方法. PPT:http://wenku.baidu.com/view/bd290294dd8 ...

  5. ANDROID_MARS学习笔记_S02_012_ANIMATION_利用AnimationListener在动画结束时删除或添加组件

    一.代码 1.xml(1)activity_main.xml <?xml version="1.0" encoding="utf-8"?> < ...

  6. MySQL show status详解

    http://www.sandzhang.com/blog/2010/04/07/mysql-show-status-explained-detail/ 要查看MySQL运行状态,要优化MySQL运行 ...

  7. BZOJ_1208_&_Codevs_1258_[HNOI2004]_宠物收养所_(平衡树/set)

    描述 http://www.lydsy.com/JudgeOnline/problem.php?id=1208 (据说codevs要更新?就不放codevs的地址了吧...) 有宠物和人,每个单位都有 ...

  8. BJOI2006狼抓兔子

    1001: [BeiJing2006]狼抓兔子 Time Limit: 15 Sec  Memory Limit: 162 MBSubmit: 9967  Solved: 2267[Submit][S ...

  9. 通过 Azure Media Encoder 降低编码成本

    John Deutscher  Azure 媒体服务首席项目经理 正如在我们的定价页面上宣布的那样,我们引入了一种只根据输出千兆字节数收取编码费用的全新定价模型.之前的/传统模型是根据输入和输出千兆字 ...

  10. awk将普通文本转换成json文件

    script1: #!/bin/bash #Date:-- #Author:eivll0m awk -F"\t" -vq='"' '{ a[$]=a[$]?a[$]:$ ...