安卓音乐播放器源码以及课程设计报告
yuyutoo 2024-10-30 06:32 6 浏览 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同步更新的了解更加全面具体,并改变了我对于软件设计的看法与认识。
相关推荐
- 墨尔本一华裔男子与亚裔男子分别失踪数日 警方寻人
-
中新网5月15日电据澳洲新快网报道,据澳大利亚维州警察局网站消息,22岁的华裔男子邓跃(Yue‘Peter’Deng,音译)失踪已6天,维州警方于当地时间13日发布寻人通告,寻求公众协助寻找邓跃。华...
- 网络交友须谨慎!美国犹他州一男子因涉嫌杀害女网友被捕
-
伊森·洪克斯克(图源网络,侵删)据美国广播公司(ABC)25日报道,美国犹他州一名男子于24日因涉嫌谋杀被捕。警方表示,这名男子主动告知警局,称其杀害了一名在网络交友软件上认识的25岁女子。雷顿警...
- 一课译词:来龙去脉(来龙去脉 的意思解释)
-
Mountainranges[Photo/SIPA]“来龙去脉”,汉语成语,本指山脉的走势和去向,现比喻一件事的前因后果(causeandeffectofanevent),可以翻译为“i...
- 高考重要考点:range(range高考用法)
-
range可以用作动词,也可以用作名词,含义特别多,在阅读理解中出现的频率很高,还经常作为完形填空的选项,而且在作文中使用是非常好的高级词汇。...
- C++20 Ranges:现代范围操作(现代c++白皮书)
-
1.引言:C++20Ranges库简介C++20引入的Ranges库是C++标准库的重要更新,旨在提供更现代化、表达力更强的方式来处理数据序列(范围,range)。Ranges库基于...
- 学习VBA,报表做到飞 第二章 数组 2.4 Filter函数
-
第二章数组2.4Filter函数Filter函数功能与autofilter函数类似,它对一个一维数组进行筛选,返回一个从0开始的数组。...
- VBA学习笔记:数组:数组相关函数—Split,Join
-
Split拆分字符串函数,语法Split(expression,字符,Limit,compare),第1参数为必写,后面3个参数都是可选项。Expression为需要拆分的数据,“字符”就是以哪个字...
- VBA如何自定义序列,学会这些方法,让你工作更轻松
-
No.1在Excel中,自定义序列是一种快速填表机制,如何有效地利用这个方法,可以大大增加工作效率。通常在操作工作表的时候,可能会输入一些很有序的序列,如果一一录入就显得十分笨拙。Excel给出了一种...
- Excel VBA入门教程1.3 数组基础(vba数组详解)
-
1.3数组使用数组和对象时,也要声明,这里说下数组的声明:'确定范围的数组,可以存储b-a+1个数,a、b为整数Dim数组名称(aTob)As数据类型Dimarr...
- 远程网络调试工具百宝箱-MobaXterm
-
MobaXterm是一个功能强大的远程网络工具百宝箱,它将所有重要的远程网络工具(SSH、Telnet、X11、RDP、VNC、FTP、MOSH、Serial等)和Unix命令(bash、ls、cat...
- AREX:携程新一代自动化回归测试工具的设计与实现
-
一、背景随着携程机票BU业务规模的不断提高,业务系统日趋复杂,各种问题和挑战也随之而来。对于研发测试团队,面临着各种效能困境,包括业务复杂度高、数据构造工作量大、回归测试全量回归、沟通成本高、测试用例...
- Windows、Android、IOS、Web自动化工具选择策略
-
Windows平台中应用UI自动化测试解决方案AutoIT是开源工具,该工具识别windows的标准控件效果不错,但是当它遇到应用中非标准控件定义的UI元素时往往就无能为力了,这个时候选择silkte...
- python自动化工具:pywinauto(python快速上手 自动化)
-
简介Pywinauto是完全由Python构建的一个模块,可以用于自动化Windows上的GUI应用程序。同时,它支持鼠标、键盘操作,在元素控件树较复杂的界面,可以辅助我们完成自动化操作。我在...
- 时下最火的 Airtest 如何测试手机 APP?
-
引言Airtest是网易出品的一款基于图像识别的自动化测试工具,主要应用在手机APP和游戏的测试。一旦使用了这个工具进行APP的自动化,你就会发现自动化测试原来是如此简单!!连接手机要进行...
- 【推荐】7个最强Appium替代工具,移动App自动化测试必备!
-
在移动应用开发日益火爆的今天,自动化测试成为了确保应用质量和用户体验的关键环节。Appium作为一款广泛应用的移动应用自动化测试工具,为测试人员所熟知。然而,在不同的测试场景和需求下,还有许多其他优...
你 发表评论:
欢迎- 一周热门
- 最近发表
- 标签列表
-
- 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)