百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 编程网 > 正文

安卓音乐播放器源码以及课程设计报告

yuyutoo 2024-10-30 06:32 1 浏览 0 评论

  1. 实验题目:音乐播放器
    二、实验目的:
  2. 学会如何使用 MediaPlayer 等媒体播放组件。
  3. 学会如何进行数据保存。
    三、总体设计
  4. 需求分析
    在设置菜单,读取 sdcard 指定目录下的所有 mp3 文件,建立播放列表,对于用户而言音乐播放器最重要的功能就是
    播放功能,在此基础上为了使用户有更好的体验,增加了切歌、暂停、设置播放模式功能。
    当目前从未播放过歌曲时,点击播放按键会默认播放列表第一首歌;
    点击前一首歌按钮,若目前播放的是第一首歌或者未播放歌曲时,则播放最后一首歌;点击下一首歌按钮,逻辑近似,当播放的是最后一首歌或者未播放歌曲时播放第一首歌。
    除此之外,考虑到用户的具体需求,在获取音乐的基础上对功能进行扩展,扫描本地音乐,
    刷新播放列表;并在播放功能的基础上添加了点击列表控制播放进度条显示歌曲进度、拖动进度条改变歌曲进度功能。
    用例图如下:


思维导图如下:

  1. 背景知识
  2. 自定义线程
  3. 权限申请
  4. 基本的重写View能力
  5. MediaPlayer工具来播放音乐
  6. SeekBar滑动条监听事件以及改变歌曲进度
  7. ListView绑定适配器展示数据以及Item点击事件
  8. Dialog弹出框
  9. 启动页的设置
  10. 界面设计

遵循界面简洁直观,操作方便快捷原则进行设计,点击右上角设置按钮会弹出选择框,用于设置播放模式。

整体布局使用LinearLayout布局,播放列表使用ListView控件,底部play_bar的布局使用RelativeLayout和LinearLayout嵌套使用,整体布局如左图,具体实现效果如右图:

ListView中Item布局如图:

  1. 设计想法

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设计
  1. 程序时序图:
  • 播放音乐时序图:
  • 暂停播放时序图:
  • 切歌时序图(正在播放):

若无歌曲播放,则直接调用mediaPlayer.setDataSource()来设置播放路径;

  1. 实现步骤
  2. 编写MusicUtils扫描本地音频文件,返回一个List<Song>集合
    Cursor cursor = context.getContentResolver().query(
    MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, null, selection,
    selectionArgs, MediaStore.Audio.AudioColumns.IS_MUSIC );
  3. 申请权限,然后在手机内存sdCard将音乐及其相关信息读取出来,在清单文件中输入下列语句来申请权限:
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
  4. 在清单文件中设置主题,并在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>
  5. 用一个ListView容器显示所有的本地音乐,在Center.java文件中定义List<Song>集合来保存获取到音频文件的相关信息,再绑定适配器来连接视图与数据
    list = MusicUtils.getMusicData(this);
    SongAdapter adapter = new SongAdapter(this, list);
    listView.setAdapter(adapter);
  6. 编写相关函数,实现播放、暂停、下一首、上一首、继续播放等功能主要调用方法为:mediaPlayer.start()、mediaPlayer.pause()、mediaPlayer.stop()、
    mediaPlayer.seekTo();
  7. 编写监听事件来控制SeekBar的更新以及改变进度,并通过自定义线程来实现UI界面的更新
  8. 设置ListView中Item点击事件
  9. 详细设计(含主要的数据结构、程序流程图、关键代码等)
  10. 主要函数
  11. 播放:musicplay(int position)
  12. 暂停:pause(int position)
  13. 继续播放:playAgain()
  14. 下一首: next()
  15. 上一首:front()
  16. 图标、歌曲名更新: update(String song , boolean is_play)
  17. 设置播放模式:showDialog(View view)
  18. 关键代码
  19. 启动页的实现:
    new Handler().postDelayed(new Runnable() {
    @Override
    public void run() {
    Intent intent = new Intent(LunchActivity.this, Center.class);
    startActivity(intent);
    finish(); }
    }, 10000);
  20. ListView点击事件:设置参数isPlayAgain = 0来标记重复点击次数,第一次点击歌曲直接播放,第二次点击时判断是否为同一个,如果不是则切歌,是则暂停;第三次点击同样需要点击是否仍为同一个,如果不是则继续切歌,如果是则继续播放;
    if ( isplaying ){
    pause(playposition);//暂停播放
    if ( playposition != position ){
    //点击不是同一首歌曲,则更换播放路径,切歌,同时isPlayAgain=0
    }else {
    isPlayAgain++;//当isPlayAgain为偶数时,继续播放;为奇数则暂停播放 }
    }else { isplaying = true; //说明开始播放歌曲
    musicplay(position);//没有播放音乐,则开始播放
    }
    流程图如下:
  1. 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(); //创建进程
  2. 自定义线程SeekBarThread
    while ( isplaying && mediaPlayer.isPlaying() ) {
    seekBar.setProgress( time * max / all_time );
    // 将SeekBar位置设置到当前播放位置
    try {
    // 每500毫秒更新一次位置
    Thread.sleep(500);
    } catch (InterruptedException e) {
    e.printStackTrace();
    }
    }
  3. 下一首,特殊情况下播放的歌曲为最后一首或还没有播放任何一首歌曲时,切歌播放的是列表第一首歌(播放第一首歌时进行上一首切歌的逻辑类似):
    if ( playposition == (list.size()-1 )|| !isplaying ){
    if ( flag ){
    mediaPlayer.stop();
    mediaPlayer.release();
    }
    musicplay(0);
    flag = true; //用于记录播放最后一首歌或第一首歌
    isplaying = true; }else { musicplay(playposition + 1 );
    }
  4. 设置弹出框:

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();

  1. 设置播放模式:定义参数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 );

  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时可以实现音频的暂停、播放以及切歌,使用户的操作更加便利,更加人性化;除了使用这个方法来进行切歌之外,还有使用固定按键来进行上述操作。

且在设置播放模式后会按照对应模式进行切歌,如单曲循环状态下,则只会重复播放设置时播放的歌曲,随机播放时则会按照一定的规律进行路径的更改,当音频数量较多时给用户呈现出的效果就是随机播放。

在实现功能过程中,曾碰到了许多问题,以下是主要问题的总结以及相关分析、解决方法:

  1. 启动页在真机上无法展示,但是在模拟器上运行良好——安卓版本问题
  2. 启动页在主题上设置后能进行显示但是应用界面的背景也随之改变——我在主题里面设置windowBackground后虽然可以有启动页的效果,但是当我拆分为两个主题样式时,就无法显示出来了,后来自己突然想到了样式的优先级大于主题,只需在主页面的Layout文件中设置一个backgroud来进行样式的设置,这个问题得以解决。
  3. 无法扫描本地sdcard,获取音乐列表——由于是在清单文件中静态申请权限,而安卓6.0及以上版本有一个安全机制是需要自己手动在手机上打开存储权限,所以导致在安卓6.0及以上版本运行应用时无法获取音频,分析LogCat后找到了错误,并通过在手机上手动授权得以解决问题。
  4. 第一次播放以及暂停后播放时seekbar没有移动——调试后发现在第一次播放或暂停后播放的时候mediaPlayer.isPlaying()为false,所以导致seekBar无法正常更新,针对这一问题对mediaPlayer.isPlaying()进行判断,分情况对time进行赋值。
  5. 播放第一首歌切上一首时会同时播放最后一首和第一首歌——在经过调试后,发现在播放第一首歌时进行切歌会跳转到front()函数,而在此函数中又会获得一个新的播放路径来代替目前的播放路径,使正播放的MediaPlayer没有被暂停销毁从而脱离控制,后来设置了boolean flag = false来记录当前播放文件是否为第一首或最后一首,并在next()和front()函数中加入对flag的判断,如果flag为true,则调用mediaPlayer.stop()来销毁旧对象。
  6. 小结与心得体会

两周课设结束,最终成品总的来说还是让自己有所收获,尤其是在最初的版本到最后的成品的变化中让我对于软件设计这一个词汇有了更新更深的认识。

在设计过程中我曾利用了BottomNavigationActivity进行布局,但在具体实现过程中发现目前我能实现的功能无法很好的支撑起这个布局,显得应用布局太大、内容太空。当我自己使用应用时体验感并不是很好,很多功能显的非常鸡肋且多余,比如在最初我设计了一个用户登录、修改密码及用户信息的功能,但是真正使用起来,给我最直观的感受就是多余且麻烦,所以在最后确定布局时我选择了以简单的一个界面进行展示,虽然布局更为简洁,但体验感却大大提高了,并且可扩展性更高。

这次课设让我认识到真正好的软件产品并不是什么功能都必须要有,只有当产品功能最少但又能满足用户大部分需求时,这才是产品的最佳状态。其余的功能都是在这个状态的基础上进行添加以满足少数需求。

当然这次课设我完成的任务只是音乐播放器最基本的一些功能,在课设结束后我也依旧可以以这个版本为基础进行功能的扩展,比如说同步歌词、专辑照片,还有均衡器的调整等,这些都是一个个关卡在等着我去解决。

所以总的来说这次课设让我受益匪浅,在一定程度上丰富了我的开发经验,并且提高了我独立解决问题的能力,有许多问题是我在自己上手开发一款软件之前从未考虑到或想到的,比如说安卓版本问题对于应用的性能展示的影响。同时也让我对于布局、自定义线程、MediaPlayer的使用以及SeekBar同步更新的了解更加全面具体,并改变了我对于软件设计的看法与认识。

相关推荐

MySQL5.5+配置主从同步并结合ThinkPHP5设置分布式数据库

前言:本文章是在同处局域网内的两台windows电脑,且MySQL是5.5以上版本下进行的一主多从同步配置,并且使用的是集成环境工具PHPStudy为例。最后就是ThinkPHP5的分布式的连接,读写...

thinkphp5多语言怎么切换(thinkphp5.1视频教程)

thinkphp5多语言进行切换的步骤:第一步,在配置文件中开启多语言配置。第二步,创建多语言目录。相关推荐:《ThinkPHP教程》第三步,编写语言包。视图代码:控制器代码:效果如下:以上就是thi...

基于 ThinkPHP5 + Bootstrap 的后台开发框架 FastAdmin

FastAdmin是一款基于ThinkPHP5+Bootstrap的极速后台开发框架。主要特性基于Auth验证的权限管理系统支持无限级父子级权限继承,父级的管理员可任意增删改子级管理员及权限设置支持单...

Thinkphp5.0 框架实现控制器向视图view赋值及视图view取值操作示

本文实例讲述了Thinkphp5.0框架实现控制器向视图view赋值及视图view取值操作。分享给大家供大家参考,具体如下:Thinkphp5.0控制器向视图view的赋值方式一(使用fetch()方...

thinkphp5实现简单评论回复功能(php评论回复功能源码下载)

由于之前写评论回复都是使用第三方插件:畅言所以也就没什么动手,现在证号在开发一个小的项目,所以就自己动手写评论回复,没写过还真不知道评论回复功能听着简单,但仔细研究起来却无法自拔,由于用户量少,所以...

ThinkPHP框架——实现定时任务,定时更新、清理数据

大家好,我是小蜗牛,今天给大家分享一下,如何用ThinkPHP5.1.*版本实现定时任务,例如凌晨12点更新数据、每隔10秒检测过期会员、每隔几分钟发送请求保证ip的活性等本次分享,主要用到一个名为E...

BeyongCms系统基于ThinkPHP5.1框架的轻量级内容管理系统

BeyongCms内容管理系统(简称BeyongCms)BeyongCms系统基于ThinkPHP5.1框架的轻量级内容管理系统,适用于企业Cms,个人站长等,针对移动App、小程序优化;提供完善简...

YimaoAdminv3企业建站系统,使用 thinkphp5.1.27 + mysql 开发

介绍YimaoAdminv3.0.0企业建站系统,使用thinkphp5.1.27+mysql开发。php要求5.6以上版本,推荐使用5.6,7.0,7.1,扩展(curl,...

ThinkAdmin-V5开发笔记(thinkpad做开发)

前言为了快速开发一款小程序管理后台,在众多的php开源后台中,最终选择了基于thinkphp5的,轻量级的thinkadmin系统,进行二次开发。该系统支持php7。文档地址ThinkAdmin-V5...

thinkphp5.0.9预处理导致的sql注入复现与详细分析

复现先搭建thinkphp5.0.9环境...

thinkphp5出现500错误怎么办(thinkphp页面错误)

thinkphp5出现500错误,如下图所示:相关推荐:《ThinkPHP教程》require():open_basedirrestrictionineffect.File(/home/ww...

Thinkphp5.0极速搭建restful风格接口层

下面是基于ThinkPHPV5.0RC4框架,以restful风格完成的新闻查询(get)、新闻增加(post)、新闻修改(put)、新闻删除(delete)等server接口层。1、下载Thin...

基于ThinkPHP5.1.34 LTS开发的快速开发框架DolphinPHP

DophinPHP(海豚PHP)是一个基于ThinkPHP5.1.34LTS开发的一套开源PHP快速开发框架,DophinPHP秉承极简、极速、极致的开发理念,为开发集成了基于数据-角色的权限管理机...

ThinkPHP5.*远程代码执行高危漏洞手工与升级修复解决方法

漏洞描述由于ThinkPHP5框架对控制器名没有进行足够的安全检测,导致在没有开启强制路由的情况下,黑客构造特定的请求,可直接GetWebShell。漏洞评级严重影响版本ThinkPHP5.0系列...

Thinkphp5代码执行学习(thinkphp 教程)

Thinkphp5代码执行学习缓存类RCE版本5.0.0<=ThinkPHP5<=5.0.10Tp框架搭建环境搭建测试payload...

取消回复欢迎 发表评论: