本文将引导大家做一个音乐播放器,在做这个Android开发实例的过程中,能够帮助大家进一步熟悉和掌握学过的ListView和其他一些组件。为了有更好的学习效果,其中很多功能我们手动实现,例如音乐播放的快进快退等。

先欣赏下本实例完成后运行的界面效果:

首先我们建立项目,我使用的SDK是Android2.2的,然后在XML中进行布局。

上方是一个ListView用来显示我们的音乐列表,中间是一个SeekBar可以拖动当前音乐的播放进度,之所以用SeekBar而不用ProgressBar是因为我们需要音乐的快进快退功能,可以拖动滑杆改变进度;还有一个TextView,用来显示当前播放歌曲的名字,时长等。最下方就是4个Button了,分别是上一曲,播放(暂停),停止,下一曲。

大家注意尽量不要在布局中出现直接显示在界面上的文字内容,我们把这些内容都放在res/values下的strings.xml中,然后分别引用它们,这样养成良好的习惯,界面与内容分离,方便调试和后期维护等。现在我们的界面如下:

然后我们把File Explorer打开,在eclipse的Window -- Show View -- Other --Android --File Explore。你也可以直接Alt+Shift+Q。

在mnt/sdcard下面,我们放个两三首歌曲,在虚拟机中暂不支持中文,导入有中文的文件会报错的。

接着我们创建一个类,做我们播放器的Service类,我就叫MusicService吧,在里面声明以下对象:

Java代码
  1. public class MusicService {
  2. private static final File MUSIC_PATH = Environment
  3. .getExternalStorageDirectory();// 找到music存放的路径。
  4. public List<String> musicList;// 存放找到的所有mp3的绝对路径。
  5. public MediaPlayer player; // 定义多媒体对象
  6. public int songNum; // 当前播放的歌曲在List中的下标
  7. public String songName; // 当前播放的歌曲名
  8. }

然后我们去加载刚才添加的MP3文件吧,这里的方式多种多样,我随便写一个简单的了:

Java代码
  1. class MusicFilter implements FilenameFilter {
  2. public boolean accept(File dir, String name) {
  3. return (name.endsWith(".mp3"));//返回当前目录所有以.mp3结尾的文件
  4. }
  5. }

在MusicService类的无参构造函数中实例化对象,并把这些MP3文件放到musicList中。

Java代码
  1. public MusicService() {
  2. musicList = new ArrayList<String>();
  3. player = new MediaPlayer();
  4. if (MUSIC_PATH.listFiles(new MusicFilter()).length > 0) {
  5. for (File file : MUSIC_PATH.listFiles(new MusicFilter())) {
  6. musicList.add(file.getAbsolutePath());
  7. }
  8. }
  9. }

我们写个方法,来设置当前播放歌曲的名字:(个人觉得这方法比较笨,但暂时没想到别的办法)

Java代码
  1. public void setPlayName(String dataSource) {
  2. File file = new File(dataSource);//假设为D:\\mm.mp3
  3. String name = file.getName();//name=mm.mp3
  4. int index = name.lastIndexOf(".");//找到最后一个.
  5. songName = name.substring(0, index);//截取为mm
  6. }

接下来就是我们Service类的基本方法了,也就是开始、暂停、停止、上一首和下一首。

我们分别使用声明的多媒体对象的start、pause、stop等方法可以完成。

Java代码
  1. public void start() {
  2. try {
  3. player.reset(); //重置多媒体
  4. String dataSource = musicList.get(songNum);//得到当前播放音乐的路径
  5. setPlayName(dataSource);//截取歌名
  6. player.setDataSource(dataSource);//为多媒体对象设置播放路径
  7. player.prepare();//准备播放
  8. player.start();//开始播放
  9. //setOnCompletionListener 当当前多媒体对象播放完成时发生的事件
  10. player.setOnCompletionListener(new OnCompletionListener() {
  11. public void onCompletion(MediaPlayer arg0) {
  12. next();//如果当前歌曲播放完毕,自动播放下一首.
  13. }
  14. });
  15. } catch (Exception e) {
  16. Log.v("MusicService", e.getMessage());
  17. }
  18. }
  19. public void next() {
  20. songNum = songNum == musicList.size() - 1 ? 0 : songNum + 1;
  21. start();
  22. }
  23. public void last() {
  24. songNum = songNum == 0 ? musicList.size() - 1 : songNum - 1;
  25. start();
  26. }
  27. public void pause() {
  28. if (player.isPlaying())
  29. player.pause();
  30. else
  31. player.start();
  32. }
  33. public void stop() {
  34. if (player.isPlaying()) {
  35. player.stop();
  36. }
  37. }

到此为止我们的Service类就写完了,接着我们去Activity中为各控件绑定事件。

在这个Activity中,最难做的一点应该就是拖动SeekBar的滑杆改变播放进度了,这里我考虑再三,用了一个Handler类来处理。

Handler在android里负责发送和处理消息。它的主要用途有:

1.按计划发送消息或执行某个Runnanble(使用POST方法)。

2.从其他线程中发送来的消息放入消息队列中,避免线程冲突(常见于更新UI线程)。

默认情况下,Handler接受的是当前线程下的消息循环实例(使用Handler(Looper looper)、Handler(Looper looper, Handler.Callback callback)可以指定线程),同时一个消息队列可以被当前线程中的多个对象进行分发、处理(在UI线程中,系统已经有一个Activity来处理了,你可以再起若干个Handler来处理)。在实例化Handler的时候,Looper可以是任意线程的,只要有Handler的指针,任何线程也都可以sendMessage。Handler对于Message的处理不是并发的。一个Looper 只有处理完一条Message才会读取下一条,所以消息的处理是阻塞形式的(handleMessage()方法里不应该有耗时操作,可以将耗时操作放在其他线程执行,操作完后发送Message(通过sendMessges方法),然后由handleMessage()更新UI)。

声明以下变量:

Java代码
  1. private Button btnStart, btnStop, btnNext, btnLast;
  2. private TextView txtInfo;
  3. private ListView listView;
  4. private SeekBar seekBar;
  5. private MusicService musicService;
  6. private MusicHandler musicHandler;// 处理改变进度条事件
  7. private MusicThread musicThread;// 自动改变进度条的线程
  8. private boolean autoChange, manulChange;// 判断是进度条是自动改变还是手动改变
  9. private boolean isPause;// 判断是从暂停中恢复还是重新播放

如有报错的可以先注释掉不用管它,然后在初始化过程中绑定事件。

这是ListView的填充方法:

Java代码
  1. private void setListViewAdapter() {
  2. List<Map<String, Object>> date = new ArrayList<Map<String, Object>>();
  3. for (String path : musicService.musicList) {
  4. Map<String, Object> map = new HashMap<String, Object>();
  5. File file = new File(path);
  6. map.put("fileName", file.getName());
  7. date.add(map);
  8. }
  9. SimpleAdapter adapter = new SimpleAdapter(this, date,
  10. android.R.layout.simple_list_item_1,
  11. new String[] { "fileName" }, new int[] { android.R.id.text1 });
  12. listView.setAdapter(adapter);
  13. }

SimpleAdapter的构造函数是:

public SimpleAdapter (Context context, List<? extends Map<String, ?>> data, int resource, String[] from, int[] to);

第一个参数context,是指在哪个Activity中显示。

第二个参数是一个泛型作为数据源,而且每一个List中的一行就代表着呈现出来的一行,Map的键就是这一行的列名,值也是有列名的。

第三个参数为资源文件,就是说要加载这个列所需要的视图资源文件,我直接引用系统内置的资源,如果你想要漂亮的样式可以自己写的。

第四个参数是一个String数组,主要是将Map对象中的名称映射到列名,一一对应。

第五个是将第四个参数的值一一对象的显示(一一对应)在接下来的int形的id数组中,这个id数组就是Layout的xml文件中命名id形成的唯一的int型标识符。

SeekBar停止拖动后的事件:

Java代码
  1. public void onStopTrackingTouch(SeekBar seekBar) { // 停止拖动
  2. int progress = seekBar.getProgress();
  3. if (!autoChange && manulChange) {
  4. int musicMax = musicService.player.getDuration(); //得到该首歌曲最长秒数
  5. int seekBarMax = seekBar.getMax();
  6. musicService.player
  7. .seekTo(musicMax * progress / seekBarMax);//跳到该曲该秒
  8. musicService.pause();
  9. autoChange = true;
  10. manulChange = false;
  11. }
  12. }

MusicHandler类的实现:

Java代码
  1. class MusicHandler extends Handler {
  2. public MusicHandler() {
  3. }
  4. @Override
  5. public void handleMessage(Message msg) {
  6. if (autoChange) {
  7. try {
  8. int position = musicService.player.getCurrentPosition();//得到当前歌曲播放进度(秒)
  9. int mMax = musicService.player.getDuration();//最大秒数
  10. int sMax = seekBar.getMax();//seekBar最大值,算百分比
  11. seekBar.setProgress(position * sMax / mMax);
  12. txtInfo.setText(setPlayInfo(position / 1000, mMax / 1000));
  13. } catch (Exception e) {
  14. e.printStackTrace();
  15. }
  16. } else {
  17. seekBar.setProgress(0);
  18. txtInfo.setText("播放已经停止");
  19. }
  20. }
  21. }
  22. //设置当前播放的信息
  23. private String setPlayInfo(int position, int max) {
  24. String info = "正在播放:  " + musicService.songName + "\t\t";
  25. //笨办法 写完才想起可以用%的,但不想改了
  26. int pMinutes = 0;
  27. while (position >= 60) {
  28. pMinutes++;
  29. position -= 60;
  30. }
  31. String now = (pMinutes < 10 ? "0" + pMinutes : pMinutes) + ":"
  32. + (position < 10 ? "0" + position : position);
  33. int mMinutes = 0;
  34. while (max >= 60) {
  35. mMinutes++;
  36. max -= 60;
  37. }
  38. String all = (mMinutes < 10 ? "0" + mMinutes : mMinutes) + ":"
  39. + (max < 10 ? "0" + max : max);
  40. return info + now + " / " + all;
  41. }

MusicThread的实现:

Java代码
  1. class MusicThread implements Runnable {
  2. @Override
  3. public void run() {
  4. while (true)
  5. try {
  6. musicHandler.sendMessage(new Message());
  7. Thread.sleep(1000);// 每间隔1秒发送一次更新消息
  8. } catch (InterruptedException e) {
  9. e.printStackTrace();
  10. }
  11. }
  12. }

Android音乐播放器的开发实例的更多相关文章

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

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

  2. Android音乐播放器源码(歌词.均衡器.收藏.qq5.0菜单.通知)

    一款Android音乐播放器源码,基本功能都实现了 qq5.0菜单(歌词.均衡器.收藏.qq5.0菜单.通知) 只有向右滑动出现,菜单键和指定按钮都还没有添加. 源码下载:http://code.66 ...

  3. 一款非常简单的android音乐播放器源码分享给大家

    一款非常简单的android音乐播放器源码分享给大家,该应用虽然很小,大家常用的播放器功能基本实现了,可能有点还不够完善,大家也可以自己完善一下,源码在源码天堂那里已经有了,大家可以到那里下载学习吧. ...

  4. Android音乐播放器开发

    今日看书,看到这个播放器,我就写了个例子,感觉还行,这个播放器能播放后缀是.MP3的音乐,这个例子在main.xml设置listView的时候,注意:android:id="@+id/and ...

  5. android 音乐播放器

    本章以音乐播放器为载体,介绍android开发中,通知模式Notification应用.主要涉及知识点Notification,seekbar,service. 1.功能需求 完善音乐播放器 有播放列 ...

  6. Android音乐播放器的设计与实现

    目录 应用开发技术及开发平台介绍 应用需求分析 应用功能设计及其描述 应用UI展示 一.应用开发技术及平台介绍 ①开发技术: 本系统是采用面向对象的软件开发方法,基于Android studio开发平 ...

  7. [ 原创 ]学习笔记-做一个Android音乐播放器是遇到的一些困难

    最近再做一个安卓的音乐播放器,是实验室里学长派的任务,我是在eclipse上进行开发的,由于没有android的基础,所以做起来困难重重. 首先是布局上的困难 1.layout里的控件属性不熟悉 2. ...

  8. 【竞品分析】Android音乐播放器的竞品分析

    迄今为止最长的一篇博客,各位看官笑纳~~ 本次分析基于Android平台,选取了几款我体验过的播放器进行比较分析.主要分为两类,一类是大而全的,功能全面,可满足用户管理歌曲.导入导出歌单等多方面需求, ...

  9. 一个简单的Android音乐播放器

    Android小白的期末作业 Android期末项目,仅用作学习使用,在线音乐部分只获取了网易云热歌榜,API来自鼻子亲了脸 传送门: GitHub 参考: anddiencn 实现功能 展示出本地的 ...

随机推荐

  1. ubuntu 添加启动器

    终于搞定了安卓开发环境,不知道折腾了多少次,多少个IDE,解决了一个问题,又冒出一个问题.烦死了,最后关头,都快放弃了,重启电脑,打开 android stuio 编译运行居然陈宫了,没有报错,why ...

  2. codeforces 711D D. Directed Roads(dfs)

    题目链接: D. Directed Roads time limit per test 2 seconds memory limit per test 256 megabytes input stan ...

  3. poj1274 The Perfect Stall (二分最大匹配)

    Description Farmer John completed his new barn just last week, complete with all the latest milking ...

  4. Linq中查询List组合相同值数量大于1

     List< select g.Key).ToList();

  5. iOS sha1加密算法

    最近在项目中使用到了网络请求签名认证的方法,于是在网上找关于OC sha1加密的方法,很快找到了一个大众使用的封装好的方法,以下代码便是 首先需要添加头文件 #import<CommonCryp ...

  6. 10Mybatis_mybatis和hibernate本质区别和应用场景

    hibernate:是一个标准的ORM框架(对象关系映射).入门门槛较高,不需要程序写sql语句,sql语句自动生产了. 对sql的优化比较困难. 应用场景:适用与需求变化不多的中小型项目中,比如后台 ...

  7. C# Winform关于控件TabControl闪烁的问题

    自己重写了一个Form,然后再该form上放一个TabControl鼠标移上去会闪烁,经过网上查找解决方案,最后总算是解决了....下面附上代码: 重写一个TabControl代码如下: using ...

  8. Google play billing(Google play 内支付)

    准备工作 1. 通过Android SDK Manager下载extras中的Google Play services和Google Play Billing Library两个包. 2. 把下载的. ...

  9. Python自动化测试 (二) ConfigParser模块读写配置文件

    ConfigParser 是Python自带的模块, 用来读写配置文件, 用法及其简单. 直接上代码,不解释,不多说. 配置文件的格式是: []包含的叫section,    section 下有op ...

  10. Microsoft Visual Studio 正忙

    简介:Microsoft Visual Studio 正忙,Microsoft Visual Studio 正在等待内部操作完成.如果经常在正常使用的情况下遇到此延迟, 请向Microsoft报告此情 ...