安卓音乐播放器源码以及课程设计报告
cac55 2024-10-29 13:11 13 浏览 0 评论
- 实验题目:音乐播放器
二、实验目的: - 学会如何使用 MediaPlayer 等媒体播放组件。
- 学会如何进行数据保存。
三、总体设计 - 需求分析
在设置菜单,读取 sdcard 指定目录下的所有 mp3 文件,建立播放列表,对于用户而言音乐播放器最重要的功能就是播放功能,在此基础上为了使用户有更好的体验,增加了切歌、暂停、设置播放模式功能。
当目前从未播放过歌曲时,点击播放按键会默认播放列表第一首歌;
点击前一首歌按钮,若目前播放的是第一首歌或者未播放歌曲时,则播放最后一首歌;点击下一首歌按钮,逻辑近似,当播放的是最后一首歌或者未播放歌曲时播放第一首歌。
除此之外,考虑到用户的具体需求,在获取音乐的基础上对功能进行扩展,扫描本地音乐,刷新播放列表;并在播放功能的基础上添加了点击列表控制播放、进度条显示歌曲进度、拖动进度条改变歌曲进度功能。
用例图如下:
思维导图如下:
- 背景知识
- 自定义线程
- 权限申请
- 基本的重写View能力
- MediaPlayer工具来播放音乐
- SeekBar滑动条监听事件以及改变歌曲进度
- ListView绑定适配器展示数据以及Item点击事件
- Dialog弹出框
- 启动页的设置
- 界面设计
遵循界面简洁直观,操作方便快捷原则进行设计,点击右上角设置按钮会弹出选择框,用于设置播放模式。
整体布局使用LinearLayout布局,播放列表使用ListView控件,底部play_bar的布局使用RelativeLayout和LinearLayout嵌套使用,整体布局如左图,具体实现效果如右图:
ListView中Item布局如图:
- 设计想法
Activity文件
- Center.java:主页面,主要包含了音乐播放器的播放暂停、继续播放、切歌等方法、SeekBar的监听事件和一些按键的点击事件
Class文件 - MusicUtils.java:实现本地sdCard中音频文件的扫描以及时间格式的转化
- SongAdapter.java:自定义的适配器,继承自ArrayAdapter,泛型指定为Song类,完成ListView控件的实现
- ToastUtil.java:封装了Toast方法
- LunchActivity.java:实现启动页
- Song.java:歌曲的实体类,是自定义的一个类,类图如下:
Layout文件
- activity_center.xml : 主界面的layout设计
- song_list.xml : 此布局包括了一个Imageview用来显示歌曲图片,三个TextView用来显示歌曲的信息
- play_bar.xml:底部播放栏的layout设计
- 程序时序图:
- 播放音乐时序图:
- 暂停播放时序图:
- 切歌时序图(正在播放):
若无歌曲播放,则直接调用mediaPlayer.setDataSource()来设置播放路径;
- 实现步骤
- 编写MusicUtils扫描本地音频文件,返回一个List<Song>集合
Cursor cursor = context.getContentResolver().query(
MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, null, selection,
selectionArgs, MediaStore.Audio.AudioColumns.IS_MUSIC ); - 申请权限,然后在手机内存sdCard将音乐及其相关信息读取出来,在清单文件中输入下列语句来申请权限:
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> - 在清单文件中设置主题,并在style文件中设置相关参数来实现启动页:
<style name="AppTheme"parent="Theme.AppCompat.Light.DarkActionBar">
<item name="colorPrimary">@color/colorPrimaryDark</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item>
<item name="android:windowBackground">@drawable/path</item>
<item name="windowNoTitle">true</item>
</style> - 用一个ListView容器显示所有的本地音乐,在Center.java文件中定义List<Song>集合来保存获取到音频文件的相关信息,再绑定适配器来连接视图与数据
list = MusicUtils.getMusicData(this);
SongAdapter adapter = new SongAdapter(this, list);
listView.setAdapter(adapter); - 编写相关函数,实现播放、暂停、下一首、上一首、继续播放等功能主要调用方法为:mediaPlayer.start()、mediaPlayer.pause()、mediaPlayer.stop()、
mediaPlayer.seekTo(); - 编写监听事件来控制SeekBar的更新以及改变进度,并通过自定义线程来实现UI界面的更新
- 设置ListView中Item点击事件
- 详细设计(含主要的数据结构、程序流程图、关键代码等)
- 主要函数
- 播放:musicplay(int position)
- 暂停:pause(int position)
- 继续播放:playAgain()
- 下一首: next()
- 上一首:front()
- 图标、歌曲名更新: update(String song , boolean is_play)
- 设置播放模式:showDialog(View view)
- 关键代码
- 启动页的实现:
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
Intent intent = new Intent(LunchActivity.this, Center.class);
startActivity(intent);
finish(); }
}, 10000); - ListView点击事件:设置参数isPlayAgain = 0来标记重复点击次数,第一次点击歌曲直接播放,第二次点击时判断是否为同一个,如果不是则切歌,是则暂停;第三次点击同样需要点击是否仍为同一个,如果不是则继续切歌,如果是则继续播放;
if ( isplaying ){
pause(playposition);//暂停播放
if ( playposition != position ){
//点击不是同一首歌曲,则更换播放路径,切歌,同时isPlayAgain=0
}else {
isPlayAgain++;//当isPlayAgain为偶数时,继续播放;为奇数则暂停播放 }
}else { isplaying = true; //说明开始播放歌曲
musicplay(position);//没有播放音乐,则开始播放
}
流程图如下:
- SeekBar进度条改变:当进度条改变时,通过seekBar的getProgress函数获取当前值,利用mediaPlayer的seekTo函数实现跳转
int time = seekBar.getProgress();
int all_time = list.get(playposition).getDuration();//获取正在播放歌曲的总长度
int max = seekBar.getMax();
mediaPlayer.seekTo(time * all_time / max );
thread = new Thread(new SeekBarThread());
thread.start(); //创建进程 - 自定义线程SeekBarThread
while ( isplaying && mediaPlayer.isPlaying() ) {
seekBar.setProgress( time * max / all_time );
// 将SeekBar位置设置到当前播放位置
try {
// 每500毫秒更新一次位置
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
} - 下一首,特殊情况下播放的歌曲为最后一首或还没有播放任何一首歌曲时,切歌播放的是列表第一首歌(播放第一首歌时进行上一首切歌的逻辑类似):
if ( playposition == (list.size()-1 )|| !isplaying ){
if ( flag ){
mediaPlayer.stop();
mediaPlayer.release();
}
musicplay(0);
flag = true; //用于记录播放最后一首歌或第一首歌
isplaying = true; }else { musicplay(playposition + 1 );
} - 设置弹出框:
AlertDialog.Builder builder1=new AlertDialog.Builder(Center.this);
builder1.setTitle("请选择播放模式");
builder1.setItems(gender, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
//对how进行赋值
ToastUtil.showMsg(Center.this,gender[which]+ how);
} }); builder1.show();
- 设置播放模式:定义参数int how = 1(默认为顺序播放)来记录当前设置播放模式,并通过点击弹出框来获取how值:how = 0为单曲循环,how = 1为顺序播放,how = 2为随机播放。
通过在musicplay()函数中调用mediaPlayer.setOnCompletionListener()来设置当前音频播放完毕后的操作:调用next()函数,SeekBar置为0。
设置模式为随机播放时,根据以下规律来确定下一首歌的标号:
if ( playposition < list.size() / 2 ){
musicplay( playposition * 2 - 1);
}else musicplay( playposition / 2 + 1 );
- 播放音乐:
mediaPlayer.reset(); //重置多媒体
mediaPlayer.setDataSource(list.get(position).getPath());
mediaPlayer.prepareAsync();//通过异步的方式装载媒体资源
mediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
@Override
public void onPrepared(MediaPlayer mp) {mediaPlayer.start();}});
//当前多媒体对象播放完成时发生的事件
mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
public void onCompletion(MediaPlayer arg0) {
//如果当前歌曲播放完毕,自动播放下一首.}
});
thread = new Thread(new SeekBarThread());
thread.start();
五、实验结果与分析
实验结果:可以实现设计的需求,进行本地音频的扫描以及播放暂停、切歌等功能,使用起来体验感良好,满足了用户的基本需求,界面如图:
试验时应用在后台运行了半小时左右,总体上可以达成列表的顺序循环播放,且SeekBar同步更新也可以实现。用户也可以滑动SeekBar来进行歌曲进度的调整。每次打开软件时,都可以正确且快速的扫描本地内存来更新歌曲列表以达到歌曲的增加与删除。在点击ListView的Item时可以实现音频的暂停、播放以及切歌,使用户的操作更加便利,更加人性化;除了使用这个方法来进行切歌之外,还有使用固定按键来进行上述操作。
且在设置播放模式后会按照对应模式进行切歌,如单曲循环状态下,则只会重复播放设置时播放的歌曲,随机播放时则会按照一定的规律进行路径的更改,当音频数量较多时给用户呈现出的效果就是随机播放。
在实现功能过程中,曾碰到了许多问题,以下是主要问题的总结以及相关分析、解决方法:
- 启动页在真机上无法展示,但是在模拟器上运行良好——安卓版本问题
- 启动页在主题上设置后能进行显示但是应用界面的背景也随之改变——我在主题里面设置windowBackground后虽然可以有启动页的效果,但是当我拆分为两个主题样式时,就无法显示出来了,后来自己突然想到了样式的优先级大于主题,只需在主页面的Layout文件中设置一个backgroud来进行样式的设置,这个问题得以解决。
- 无法扫描本地sdcard,获取音乐列表——由于是在清单文件中静态申请权限,而安卓6.0及以上版本有一个安全机制是需要自己手动在手机上打开存储权限,所以导致在安卓6.0及以上版本运行应用时无法获取音频,分析LogCat后找到了错误,并通过在手机上手动授权得以解决问题。
- 第一次播放以及暂停后播放时seekbar没有移动——调试后发现在第一次播放或暂停后播放的时候mediaPlayer.isPlaying()为false,所以导致seekBar无法正常更新,针对这一问题对mediaPlayer.isPlaying()进行判断,分情况对time进行赋值。
- 播放第一首歌切上一首时会同时播放最后一首和第一首歌——在经过调试后,发现在播放第一首歌时进行切歌会跳转到front()函数,而在此函数中又会获得一个新的播放路径来代替目前的播放路径,使正播放的MediaPlayer没有被暂停销毁从而脱离控制,后来设置了boolean flag = false来记录当前播放文件是否为第一首或最后一首,并在next()和front()函数中加入对flag的判断,如果flag为true,则调用mediaPlayer.stop()来销毁旧对象。
- 小结与心得体会
两周课设结束,最终成品总的来说还是让自己有所收获,尤其是在最初的版本到最后的成品的变化中让我对于软件设计这一个词汇有了更新更深的认识。
在设计过程中我曾利用了BottomNavigationActivity进行布局,但在具体实现过程中发现目前我能实现的功能无法很好的支撑起这个布局,显得应用布局太大、内容太空。当我自己使用应用时体验感并不是很好,很多功能显的非常鸡肋且多余,比如在最初我设计了一个用户登录、修改密码及用户信息的功能,但是真正使用起来,给我最直观的感受就是多余且麻烦,所以在最后确定布局时我选择了以简单的一个界面进行展示,虽然布局更为简洁,但体验感却大大提高了,并且可扩展性更高。
这次课设让我认识到真正好的软件产品并不是什么功能都必须要有,只有当产品功能最少但又能满足用户大部分需求时,这才是产品的最佳状态。其余的功能都是在这个状态的基础上进行添加以满足少数需求。
当然这次课设我完成的任务只是音乐播放器最基本的一些功能,在课设结束后我也依旧可以以这个版本为基础进行功能的扩展,比如说同步歌词、专辑照片,还有均衡器的调整等,这些都是一个个关卡在等着我去解决。
所以总的来说这次课设让我受益匪浅,在一定程度上丰富了我的开发经验,并且提高了我独立解决问题的能力,有许多问题是我在自己上手开发一款软件之前从未考虑到或想到的,比如说安卓版本问题对于应用的性能展示的影响。同时也让我对于布局、自定义线程、MediaPlayer的使用以及SeekBar同步更新的了解更加全面具体,并改变了我对于软件设计的看法与认识。
相关推荐
- Mac电脑强制删除任何软件方法-含自启动应用
-
对于打工者来说,进入企业上班使用的电脑大概率是会被监控起来,比如各种流行的数据防泄漏DLP,奇安信天擎,甚至360安全卫士,这些安全软件你想卸载是非常困难的,甚至卸载后它自己又安装回来了,并且还在你不...
- Linux基础知识 | 文件与目录大全讲解
-
1.linux文件权限与目录配置1.文件属性Linux一般将文件可存取的身份分为三个类别,分别是owner/group/others,且三种身份各read/write/execute等权限文...
- 文件保护不妥协:2025 年 10 款顶级加密工具推荐
-
数据安全无小事,2025年这10款加密工具凭借独特功能脱颖而出,从个人到企业场景全覆盖,第一款为Ping32,其余为国外英文软件。1.Ping32企业级加密核心工具,支持200+文件格...
- 省心省力 一个软件搞定系统维护_省心安装在哪里能找到
-
◆系统类似于我们居住的房间,需要经常打理才能保持清洁、高效。虽然它本身也自带一些清理和优化的工具,但借助于好用的第三方工具来执行这方面的任务,会更让人省心省力。下面笔者就为大家介绍一款集多项功能于一身...
- JAVA程序员常用的几个工具类_java程序员一般用什么软件写程序
-
好的工具做起事来常常事半功倍,下面介绍几个开发中常用到的工具类,收藏一下,也许后面真的会用到。字符串处理:org.apache.commons.lang.StringUtilsisBlank(Char...
- 手工解决Windows10的若干难题_windows10系统卡顿怎么解决
-
【电脑报在线】很多朋友已经开始使用Win10,估计还只是测试版本的原因,使用过程中难免会出现一些问题,这里介绍解决一些解决难题的技巧。技巧1:让ProjectSpartan“重归正途”从10074...
- System32文件夹千万不能删除,看完这篇你就知道为什么了
-
C:\Windows\System32目录是Windows操作系统的关键部分,重要的系统文件存储在该目录中。网上的一些恶作剧者可能会告诉你删除它,但你不应该尝试去操作,如果你尝试的话,我们会告诉你会发...
- Windows.old 文件夹:系统备份的解析与安全删除指南
-
Windows.old是Windows系统升级(如Win10升Win11)或重装时,系统自动在C盘创建的备份文件夹,其核心作用是保留旧系统的文件、程序与配置,为“回退旧系统”提供保...
- 遇到疑难杂症?Windows 10回收站问题巧解决
-
回收站是Windows10的一个重要组件。然而,我们在使用过程中,可能会遇到一些问题。例如,不论回收站里有没有文件,都显示同一个图标,让人无法判别回收站的空和满的真实情况;没有了像Windows7...
- 卸载软件怎么彻底删掉?简单几个步骤彻底卸载,电脑小白看过来
-
日常工作学习生活中,我们需要在安装一些软件程序,但随着软件的更新迭代速度,很多时候我们需要重新下载安装新的程序,这时就需要将旧的一些软件程序进行卸载。但是卸载软件虽然很简单,但是很多小伙伴们表示卸载不...
- 用不上就删!如何完全卸载OneDrive?
-
作为Windows10自带的云盘,OneDrive为资料的自动备份和同步提供了方便。然而,从隐私或其他方面考虑,有些人不愿意使用OneDrive。但Windows10本身不提供直接卸载OneDri...
- 【Linux知识】Linux下快速删除大量文件/文件夹方法
-
在Linux下,如果需要快速删除大量文件或文件夹,可以使用如下方法:使用rm命令删除文件:可以使用rm命令删除文件,例如:rm-rf/path/to/directory/*这个命令会递...
- 清理系统不用第三方工具_清理系统垃圾用什么软件
-
清理优化系统一定要借助于优化工具吗?其实,手动优化系统也没有那么神秘,掌握了方法和技巧,系统清理也是一件简单和随心的事。一方面要为每一个可能产生累赘的文件找到清理的方法,另一方面要寻找能够提高工作效率...
- 系统小技巧:软件卸载不了?这里办法多
-
在正常情况下,我们都是通过软件程序组中的卸载图标,或利用控制面板中的“程序和功能”模块来卸载软件的。但有时,我们也会发现利用卸载图标无法卸载软件或者卸载图标干脆丢失找不到了,甚至控制面板中卸载软件的功...
- 麒麟系统无法删除文件夹_麒麟系统删除文件权限不够
-
删除文件夹方法例:sudorm-rf文件夹名称。删除文件方法例:sudorm-r文件名包括扩展名。如果没有权限,给文件夹加一下权限再删。加最高权限chmod775文件名加可执行权限...
你 发表评论:
欢迎- 一周热门
- 最近发表
- 标签列表
-
- 如何绘制折线图 (52)
- javaabstract (48)
- 新浪微博头像 (53)
- grub4dos (66)
- s扫描器 (51)
- httpfile dll (48)
- ps实例教程 (55)
- taskmgr (51)
- s spline (61)
- vnc远程控制 (47)
- 数据丢失 (47)
- wbem (57)
- flac文件 (72)
- 网页制作基础教程 (53)
- 镜像文件刻录 (61)
- ug5 0软件免费下载 (78)
- debian下载 (53)
- ubuntu10 04 (60)
- web qq登录 (59)
- 笔记本变成无线路由 (52)
- flash player 11 4 (50)
- 右键菜单清理 (78)
- cuteftp 注册码 (57)
- ospf协议 (53)
- ms17 010 下载 (60)