Android应用开发--MP3音乐播放器Service实现

Android应用开发--MP3音乐播放器Service实现
2013年5月29日简、美音乐播放器开发记录

让网友们久等啦,关于简、美音乐播放器的开发,最重要的Service类总算是要发博了。关于Android五大组件之一的Service在音乐播放器开发中得到了很好的应用,不仅是Service,广播(Broadcast)、Activity、Content Provider都会在此次开发中用到。所以说对于Android的一个很好的练手项目,音乐播放器是毋庸置疑的。上一篇,主要介绍的是播放界面的业务逻辑实现,不过这些业务逻辑都是以Service为中心的。

  
package com.wwj.sb.service;

import java.util.List;

import android.annotation.SuppressLint;
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.OnPreparedListener;
import android.os.Handler;
import android.os.IBinder;
import android.util.Log;

import com.wwj.sb.activity.PlayerActivity;
import com.wwj.sb.domain.AppConstant;
import com.wwj.sb.domain.Mp3Info;
import com.wwj.sb.utils.MediaUtil;
/***
 * 2013/5/25
 * @author wwj
 * 音乐播放服务
 */
@SuppressLint("NewApi")
public class PlayerService extends Service {
	private MediaPlayer mediaPlayer; // 媒体播放器对象
	private String path; 			// 音乐文件路径
	private int msg;
	private boolean isPause; 		// 暂停状态
	private int current = 0; 		// 记录当前正在播放的音乐
	private List<Mp3Info> mp3Infos;	//存放Mp3Info对象的集合
	private int status = 3;			//播放状态,默认为顺序播放
	private MyReceiver myReceiver;	//自定义广播接收器
	private int currentTime;		//当前播放进度
	private int duration;			//播放长度
	
	//服务要发送的一些Action
	public static final String UPDATE_ACTION = "com.wwj.action.UPDATE_ACTION";	//更新动作
	public static final String CTL_ACTION = "com.wwj.action.CTL_ACTION";		//控制动作
	public static final String MUSIC_CURRENT = "com.wwj.action.MUSIC_CURRENT";	//当前音乐播放时间更新动作
	public static final String MUSIC_DURATION = "com.wwj.action.MUSIC_DURATION";//新音乐长度更新动作
	
	/**
	 * handler用来接收消息,来发送广播更新播放时间
	 */
	private Handler handler = new Handler() {
		public void handleMessage(android.os.Message msg) {
			if (msg.what == 1) {
				if(mediaPlayer != null) {
					currentTime = mediaPlayer.getCurrentPosition(); // 获取当前音乐播放的位置
					Intent intent = new Intent();
					intent.setAction(MUSIC_CURRENT);
					intent.putExtra("currentTime", currentTime);
					sendBroadcast(intent); // 给PlayerActivity发送广播
					handler.sendEmptyMessageDelayed(1, 1000);
				}
				
			}
		};
	};

	@Override
	public void onCreate() {
		super.onCreate();
		Log.d("service", "service created");
		mediaPlayer = new MediaPlayer();
		mp3Infos = MediaUtil.getMp3Infos(PlayerService.this);
		

		/**
		 * 设置音乐播放完成时的监听器
		 */
		mediaPlayer.setOnCompletionListener(new OnCompletionListener() {

			@Override
			public void onCompletion(MediaPlayer mp) {
				if (status == 1) { // 单曲循环
					mediaPlayer.start();
				} else if (status == 2) { // 全部循环
					current++;
					if(current > mp3Infos.size() - 1) {	//变为第一首的位置继续播放
						current = 0;
					}
					Intent sendIntent = new Intent(UPDATE_ACTION);
					sendIntent.putExtra("current", current);
					// 发送广播,将被Activity组件中的BroadcastReceiver接收到
					sendBroadcast(sendIntent);
					path = mp3Infos.get(current).getUrl();
					play(0);
				} else if (status == 3) { // 顺序播放
					current++;	//下一首位置
					if (current <= mp3Infos.size() - 1) {
						Intent sendIntent = new Intent(UPDATE_ACTION);
						sendIntent.putExtra("current", current);
						// 发送广播,将被Activity组件中的BroadcastReceiver接收到
						sendBroadcast(sendIntent);
						path = mp3Infos.get(current).getUrl();
						play(0);
					}else {
						mediaPlayer.seekTo(0);
						current = 0;
						Intent sendIntent = new Intent(UPDATE_ACTION);
						sendIntent.putExtra("current", current);
						// 发送广播,将被Activity组件中的BroadcastReceiver接收到
						sendBroadcast(sendIntent);
					}
				} else if(status == 4) {	//随机播放
					current = getRandomIndex(mp3Infos.size() - 1);
					System.out.println("currentIndex ->" + current);
					Intent sendIntent = new Intent(UPDATE_ACTION);
					sendIntent.putExtra("current", current);
					// 发送广播,将被Activity组件中的BroadcastReceiver接收到
					sendBroadcast(sendIntent);
					path = mp3Infos.get(current).getUrl();
					play(0);
				}
			}
		});

		myReceiver = new MyReceiver();
		IntentFilter filter = new IntentFilter();
		filter.addAction(PlayerActivity.CTL_ACTION);
		registerReceiver(myReceiver, filter);
	}

	/**
	 * 获取随机位置
	 * @param end
	 * @return
	 */
	protected int getRandomIndex(int end) {
		int index = (int) (Math.random() * end);
		return index;
	}

	@Override
	public IBinder onBind(Intent arg0) {
		return null;
	}

	@Override
	public void onStart(Intent intent, int startId) {
		path = intent.getStringExtra("url");		//歌曲路径
		current = intent.getIntExtra("listPosition", -1);	//当前播放歌曲的在mp3Infos的位置
		msg = intent.getIntExtra("MSG", 0);			//播放信息
		if (msg == AppConstant.PlayerMsg.PLAY_MSG) {	//直接播放音乐
			play(0);
		} else if (msg == AppConstant.PlayerMsg.PAUSE_MSG) {	//暂停
			pause();	
		} else if (msg == AppConstant.PlayerMsg.STOP_MSG) {		//停止
			stop();
		} else if (msg == AppConstant.PlayerMsg.CONTINUE_MSG) {	//继续播放
			resume();	
		} else if (msg == AppConstant.PlayerMsg.PRIVIOUS_MSG) {	//上一首
			previous();
		} else if (msg == AppConstant.PlayerMsg.NEXT_MSG) {		//下一首
			next();
		} else if (msg == AppConstant.PlayerMsg.PROGRESS_CHANGE) {	//进度更新
			currentTime = intent.getIntExtra("progress", -1);
			play(currentTime);
		} else if (msg == AppConstant.PlayerMsg.PLAYING_MSG) {
			handler.sendEmptyMessage(1);
		}
		super.onStart(intent, startId);
	}

	/**
	 * 播放音乐
	 * 
	 * @param position
	 */
	private void play(int currentTime) {
		try {
			mediaPlayer.reset();// 把各项参数恢复到初始状态
			mediaPlayer.setDataSource(path);
			mediaPlayer.prepare(); // 进行缓冲
			mediaPlayer.setOnPreparedListener(new PreparedListener(currentTime));// 注册一个监听器
			handler.sendEmptyMessage(1);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	/**
	 * 暂停音乐
	 */
	private void pause() {
		if (mediaPlayer != null && mediaPlayer.isPlaying()) {
			mediaPlayer.pause();
			isPause = true;
		}
	}

	private void resume() {
		if (isPause) {
			mediaPlayer.start();
			isPause = false;
		}
	}

	/**
	 * 上一首
	 */
	private void previous() {
		Intent sendIntent = new Intent(UPDATE_ACTION);
		sendIntent.putExtra("current", current);
		// 发送广播,将被Activity组件中的BroadcastReceiver接收到
		sendBroadcast(sendIntent);
		play(0);
	}

	/**
	 * 下一首
	 */
	private void next() {
		Intent sendIntent = new Intent(UPDATE_ACTION);
		sendIntent.putExtra("current", current);
		// 发送广播,将被Activity组件中的BroadcastReceiver接收到
		sendBroadcast(sendIntent);
		play(0);
	}

	/**
	 * 停止音乐
	 */
	private void stop() {
		if (mediaPlayer != null) {
			mediaPlayer.stop();
			try {
				mediaPlayer.prepare(); // 在调用stop后如果需要再次通过start进行播放,需要之前调用prepare函数
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}

	@Override
	public void onDestroy() {
		if (mediaPlayer != null) {
			mediaPlayer.stop();
			mediaPlayer.release();
			mediaPlayer = null;
		}
		
	}

	/**
	 * 
	 * 实现一个OnPrepareLister接口,当音乐准备好的时候开始播放
	 * 
	 */
	private final class PreparedListener implements OnPreparedListener {
		private int currentTime;

		public PreparedListener(int currentTime) {
			this.currentTime = currentTime;
		}

		@Override
		public void onPrepared(MediaPlayer mp) {
			mediaPlayer.start(); // 开始播放
			if (currentTime > 0) { // 如果音乐不是从头播放
				mediaPlayer.seekTo(currentTime);
			}
			Intent intent = new Intent();
			intent.setAction(MUSIC_DURATION);
			duration = mediaPlayer.getDuration();
			intent.putExtra("duration", duration);	//通过Intent来传递歌曲的总长度
			sendBroadcast(intent);
		}
	}

	public class MyReceiver extends BroadcastReceiver {

		@Override
		public void onReceive(Context context, Intent intent) {
			int control = intent.getIntExtra("control", -1);
			switch (control) {
			case 1:
				status = 1; // 将播放状态置为1表示:单曲循环
				break;
			case 2:
				status = 2;	//将播放状态置为2表示:全部循环
				break;
			case 3:
				status = 3;	//将播放状态置为3表示:顺序播放
				break;
			case 4:
				status = 4;	//将播放状态置为4表示:随机播放
				break;
			}
		}
	}

}

以上的代码要注意的是在Service在被调用startService()方法会在回调onStart(),服务是不会被多次创建的,但会多次调用onStart方法,然而通过Intent传过来的数据,也只能在onStart方法内来接收。
似乎关于Service类没什么可说的,简单来说服务是我们看不见的东西,只是在后台不断运行的程序,音乐播放通过服务来实现,才不会在界面不可见的时候停掉,这是音乐播放器使用Service的原因。
第一阶段的音乐播放器开发已经到现在全部介绍完,第二阶段会实现歌词的显示和网络相关的下载和搜索,在这一阶段也会对UI进行一些细微的美化,尽量去尝试实现更炫的效果,比如提供主题的切换,界面切换的动画等等。小巫需要继续去学习,然后把所有东西分享给学习Android的朋友们,感谢你们的关注,让我们一起共同学习进步。
第二阶段具体会什么时候启动,还没有明确的时间,因为最近开始忙起来了,所以尽情等待吧。哇咔咔



  • 40
    点赞
  • 54
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 39
    评论
好的,我知道您的问题是关于Python3和pygame开发的音乐播放器。这是一个简单的音乐播放器,使用Python3和pygame库开发。它可以播放MP3格式的音乐文件,具有基本的播放、暂停、停止、下一曲和上一曲等功能。 以下是代码示例: ```python import pygame import os import time class musicplayer: def __init__(self): pygame.init() pygame.mixer.init() self.clock = pygame.time.Clock() self.screen = pygame.display.set_mode((320, 240)) def play(self, music): pygame.mixer.music.load(music) pygame.mixer.music.play() def pause(self): pygame.mixer.music.pause() def unpause(self): pygame.mixer.music.unpause() def stop(self): pygame.mixer.music.stop() def next(self, musiclist, index): index += 1 if index >= len(musiclist): index = 0 self.play(musiclist[index]) return index def prev(self, musiclist, index): index -= 1 if index < 0: index = len(musiclist) - 1 self.play(musiclist[index]) return index def main(): musiclist = ["music1.mp3", "music2.mp3", "music3.mp3"] index = 0 mp = musicplayer() mp.play(musiclist[index]) while True: mp.clock.tick(60) for event in pygame.event.get(): if event.type == pygame.QUIT: mp.stop() pygame.quit() return if event.type == pygame.KEYDOWN: if event.key == pygame.K_SPACE: if pygame.mixer.music.get_busy(): mp.pause() else: mp.unpause() elif event.key == pygame.K_ESCAPE: mp.stop() pygame.quit() return elif event.key == pygame.K_RIGHT: index = mp.next(musiclist, index) elif event.key == pygame.K_LEFT: index = mp.prev(musiclist, index) if __name__ == "__main__": main() ``` 这个音乐播放器使用了pygame库来实现音乐播放和界面显示。它定义了一个`musicplayer`类来管理音乐播放器的各项功能,包括播放、暂停、停止、下一曲和上一曲等。在主程序中,我们可以设置要播放的音乐列表,然后通过按键来控制音乐播放器的各项功能。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 39
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小巫技术博客

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值