安卓音乐播放器源码以及课程设计报告
yuyutoo 2024-10-30 06:32 3 浏览 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同步更新的了解更加全面具体,并改变了我对于软件设计的看法与认识。
相关推荐
- Mysql和Oracle实现序列自增(oracle创建序列的sql)
-
Mysql和Oracle实现序列自增/*ORACLE设置自增序列oracle本身不支持如mysql的AUTO_INCREMENT自增方式,我们可以用序列加触发器的形式实现,假如有一个表T_WORKM...
- 关于Oracle数据库12c 新特性总结(oracle数据库19c与12c)
-
概述今天主要简单介绍一下Oracle12c的一些新特性,仅供参考。参考:http://docs.oracle.com/database/121/NEWFT/chapter12102.htm#NEWFT...
- MySQL CREATE TABLE 简单设计模板交流
-
推荐用MySQL8.0(2018/4/19发布,开发者说同比5.7快2倍)或同类型以上版本....
- mysql学习9:创建数据库(mysql5.5创建数据库)
-
前言:我也是在学习过程中,不对的地方请谅解showdatabases;#查看数据库表createdatabasename...
- MySQL面试题-CREATE TABLE AS 与CREATE TABLE LIKE的区别
-
执行"CREATETABLE新表ASSELECT*FROM原表;"后,新表与原表的字段一致,但主键、索引不会复制到新表,会把原表的表记录复制到新表。...
- Nike Dunk High Volt 和 Bright Spruce 预计将于 12 月推出
-
在街上看到的PandaDunk的超载可能让一些球鞋迷们望而却步,但Dunk的浪潮仍然强劲,看不到尽头。我们看到的很多版本都是为女性和儿童制作的,这种新配色为后者引入了一种令人耳目一新的新选择,而...
- 美国多功能舰载雷达及美国海军舰载多功能雷达系统技术介绍
-
多功能雷达AN/SPY-1的特性和技术能力,该雷达已经在美国海军服役了30多年,其修改-AN/SPY-1A、AN/SPY-1B(V)、AN/SPY-1D、AN/SPY-1D(V),以及雷神...
- 汽车音响怎么玩,安装技术知识(汽车音响怎么玩,安装技术知识视频)
-
全面分析汽车音响使用或安装技术常识一:主机是大多数人最熟习的音响器材,有关主机的各种性能及规格,也是耳熟能详的事,以下是一些在使用或安装时,比较需要注意的事项:LOUDNESS:几年前的主机,此按...
- 【推荐】ProAc Response系列扬声器逐个看
-
有考牌(公认好声音)扬声器之称ProAcTablette小音箱,相信不少音响发烧友都曾经,或者现在依然持有,正当大家逐渐掌握Tablette的摆位设定与器材配搭之后,下一步就会考虑升级至表现更全...
- #本站首晒# 漂洋过海来看你 — BLACK&DECKER 百得 BDH2000L无绳吸尘器 开箱
-
作者:初吻给了烟sco混迹张大妈时日不短了,手没少剁。家里有了汪星人,吸尘器使用频率相当高,偶尔零星打扫用卧式的实在麻烦(汪星人:你这分明是找借口,我掉毛是满屋子都有,铲屎君都是用卧式满屋子吸的,你...
- 专题|一个品牌一件产品(英国篇)之Quested(罗杰之声)
-
Quested(罗杰之声)代表产品:Q212FS品牌介绍Quested(罗杰之声)是录音监听领域的传奇品牌,由英国录音师RogerQuested于1985年创立。在成立Quested之前,Roger...
- 常用半导体中英对照表(建议收藏)(半导体英文术语)
-
作为一个源自国外的技术,半导体产业涉及许多英文术语。加之从业者很多都有海外经历或习惯于用英文表达相关技术和工艺节点,这就导致许多英文术语翻译成中文后,仍有不少人照应不上或不知如何翻译。为此,我们整理了...
- Fyne Audio F502SP 2.5音路低音反射式落地音箱评测
-
FyneAudio的F500系列,有新成员了!不过,新成员不是新的款式,却是根据原有款式提出特别版。特别版产品在原有型号后标注了SP字样,意思是SpecialProduction。Fyne一共推出...
- 有哪些免费的内存数据库(In-Memory Database)
-
以下是一些常见的免费的内存数据库:1.Redis:Redis是一个开源的内存数据库,它支持多种数据结构,如字符串、哈希表、列表、集合和有序集合。Redis提供了快速的读写操作,并且支持持久化数据到磁...
- RazorSQL Mac版(SQL数据库查询工具)
-
RazorSQLMac特别版是一款看似简单实则功能非常出色的SQL数据库查询、编辑、浏览和管理工具。RazorSQLformac特别版可以帮你管理多个数据库,支持主流的30多种数据库,包括Ca...
你 发表评论:
欢迎- 一周热门
-
-
前端面试:iframe 的优缺点? iframe有那些缺点
-
带斜线的表头制作好了,如何填充内容?这几种方法你更喜欢哪个?
-
漫学笔记之PHP.ini常用的配置信息
-
其实模版网站在开发工作中很重要,推荐几个参考站给大家
-
推荐7个模板代码和其他游戏源码下载的网址
-
[干货] JAVA - JVM - 2 内存两分 [干货]+java+-+jvm+-+2+内存两分吗
-
正在学习使用python搭建自动化测试框架?这个系统包你可能会用到
-
织梦(Dedecms)建站教程 织梦建站详细步骤
-
【开源分享】2024PHP在线客服系统源码(搭建教程+终身使用)
-
2024PHP在线客服系统源码+完全开源 带详细搭建教程
-
- 最近发表
-
- Mysql和Oracle实现序列自增(oracle创建序列的sql)
- 关于Oracle数据库12c 新特性总结(oracle数据库19c与12c)
- MySQL CREATE TABLE 简单设计模板交流
- mysql学习9:创建数据库(mysql5.5创建数据库)
- MySQL面试题-CREATE TABLE AS 与CREATE TABLE LIKE的区别
- Nike Dunk High Volt 和 Bright Spruce 预计将于 12 月推出
- 美国多功能舰载雷达及美国海军舰载多功能雷达系统技术介绍
- 汽车音响怎么玩,安装技术知识(汽车音响怎么玩,安装技术知识视频)
- 【推荐】ProAc Response系列扬声器逐个看
- #本站首晒# 漂洋过海来看你 — BLACK&DECKER 百得 BDH2000L无绳吸尘器 开箱
- 标签列表
-
- mybatis plus (70)
- scheduledtask (71)
- css滚动条 (60)
- java学生成绩管理系统 (59)
- 结构体数组 (69)
- databasemetadata (64)
- javastatic (68)
- jsp实用教程 (53)
- fontawesome (57)
- widget开发 (57)
- vb net教程 (62)
- hibernate 教程 (63)
- case语句 (57)
- svn连接 (74)
- directoryindex (69)
- session timeout (58)
- textbox换行 (67)
- extension_dir (64)
- linearlayout (58)
- vba高级教程 (75)
- iframe用法 (58)
- sqlparameter (59)
- trim函数 (59)
- flex布局 (63)
- contextloaderlistener (56)