android音乐播放器开发 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";

	@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);
	}

}
时间: 2024-10-20 09:29:41

android音乐播放器开发 SweetMusicPlayer 播放本地音乐的相关文章

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

在一份书面的使用MediaPlayer播放音乐, http://blog.csdn.net/huweigoodboy/article/details/39862773.假设没有本地歌词怎么办?如今来将一下载入在线歌词.好了,还是用那张图. 在实现这个功能的时候,lz尝试过baidu api,歌词迷api,后来选用了歌词迷api.尽管还是资源不全.并且还有非常多错误. 特别头疼的是有时候歌词竟然不分行.解析起来简直难受. 歌词迷api歌词查询地址:http://geci.me/api/lyric/

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

上一篇写了使用MediaPlayer播放音乐,http://blog.csdn.net/huweigoodboy/article/details/39861539,现在来将一下加载本地歌词.好了,还是用那张图. 一,从内存卡上匹配歌词 将会从以下路径匹配 1)  SweetMusicPlayer/Lyrics/ 2)  歌曲同级目录下 3)  歌曲父级目录/lryics(Lryic加不加s,首字母大小与否又分情况) LrcContent package com.huwei.sweetmusicp

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

上一篇写了播放器的整体实现思路,http://blog.csdn.net/huweigoodboy/article/details/39855653,现在来总结下加载歌曲列表. 比较好的实现思路就是,自己维护一个SQLite数据库,然后音乐信息都从sd卡上扫描,好处有很多,但是这样做的话代码量会比较大,写了一段扫描sd卡的代码,然后发现扫描音乐的速度简直慢的惊人,可能自己的目录太多,太深,目前还没想到一个比较好的算法去快速扫描sd卡. 楼主比较偷懒,android自己本身有一个关于媒体信息的数据

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

上一篇写了播放器的总体实现思路,http://blog.csdn.net/huweigoodboy/article/details/39855653,如今来总结下载入歌曲列表. 代码地址:https://github.com/huweigoodboy/SweetMusicPlayer 比較好的实现思路就是.自己维护一个SQLite数据库,然后音乐信息都从sd卡上扫描,优点有非常多,可是这样做的话代码量会比較大,写了一段扫描sd卡的代码.然后发现扫描音乐的速度简直慢的惊人,可能自己的文件夹太多,太

android音乐播放器开发 SweetMusicPlayer 智能加载在线歌词

上一篇写了使用MediaPlayer播放音乐, http://blog.csdn.net/huweigoodboy/article/details/39862773,如果没有本地歌词怎么办?现在来将一下加载在线歌词.好了,还是用那张图. 在实现这个功能的时候,lz尝试过baidu api,歌词迷api,后来选用了歌词迷api,虽然还是资源不全,而且还有很多错误.特别头疼的是有时候歌词居然不分行,解析起来简直难受. 歌词迷api歌词查询地址:http://geci.me/api/lyric/ 比如

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

上一篇写了如何在线匹配歌词,http://blog.csdn.net/huweigoodboy/article/details/39878063,现在来讲讲摇一摇功能开发. 同样用了一个Service去实现摇一摇. ShakeListener继承自SensorEventListener,当加速度感应器感受到重力变化,就去通知onShakeListener调用onShake(), 在震动的同时随机一首歌. 一,加速度感应器 在这里需要设置一个速度阈值和时间间隔,控制一定的时间间隔才能触发第二次震动

android音乐播放器开发教程

android音乐播放器开发教程 android音乐播放器开发教程,布布扣,bubuko.com

HTML5之audio实战,网页音乐播放器开发

今天我们就基于 HTML5 audio  来,开发一个网页音乐播放器. 在HTML5 新特性中,audio .video 是我们比较关心的 新 元素,我们终于可以脱离 Flash ,来开发音频.视频播放器了,对于 一个HTML 新元素,无非就是 属性.事件 .方法等等,关于audio 的具体的属性.事件 .方法,请谷歌. 看我们的HTML代码: audio.html <!DOCTYPE html> <html> <head> <meta charset="

仿酷狗音乐播放器开发日志二十一 开发动态调色板控件(附源代码)

转载请说明原出处,谢谢~~ 上一篇仿酷狗日志结束后,整个换肤功能就仅仅剩下调色板功能没有做了.我本以为会非常easy.可是研究了酷狗的调色板功能后发现不是那么简单的事情.首先看一下酷狗的调色板的样子: watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvemh1aG9uZ3NodQ==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" > waterm