安卓系统音乐播放器 - 图文

更新时间:2024-05-04 00:01:01 阅读量: 综合文库 文档下载

说明:文章内容仅供预览,部分内容可能不全。下载后的文档,内容与下面显示的完全一致。下载之前请确认下面内容是否您想要的,是否完整无缺。

武汉理工大学华夏学院 课程设计报告书

课程名称:

操作系统原理

题 目:基于Android手机平台的音乐播放器 系 名: 信息工程系

专业班级:

姓 名: 学 号: 指导教师:

2012年 7月 4 日

课程设计任务书

学生姓名: 专业班级: 指导教师: 工作单位: 设计题目:基于Android平台的音乐播放器的歌词显示功能设计 初始条件:

Linux操作系统,Android开发环境,Java编译环境,文件存储操作

要求完成的主要任务:

主要任务:

现今社会生活紧张,而欣赏音乐是其中最好的舒缓压力的方式之一,本项目的目的是开发一个可以播放主流音乐文件格式的播放器的歌词显示模块,要求音乐播放器能够播放Mp3,Wav多种格式的音乐文件,能够显示正在播放的音乐歌词,并且能够控制播放,暂停,停止,上一曲,下一曲,音量调节,要求视觉外观美观,操作简单。

本项目是一款基于Android手机平台的音乐播放器的子模块,使Android手机拥有个性的多媒体播放器,使手机显得更生动灵活化,与人们更为接近,让手机主人随时随地处于音乐视频的旋律之中。使人们的生活更加多样化。也使设计者更加熟练Android的技术和其它在市场上的特点

设计报告撰写格式要求:

1设计题目与要求 2 设计思想

3系统结构 4 数据结构的说明和模块的算法流程图

5 使用说明书(即用户手册):内容包含如何登录、退出、读、写等操作说明

6 运行结果和结果分析(其中包括实验的检查结果、程序的运行情况)

7 自我评价与总结 8 附录:程序清单,注意加注释(包括关键字、方法、变量等),在每个模块前加注释;

时间安排

7月1日 布置课程设计任务;分配题目后,查阅资料、 准备程序; 7月 2~7月4 日上机调试程序、书写课程设计报告;

7月5 日 提交课程设计报告及相关文档。

指 导 教 师 签 字: 2012年 6月 20日

系 主 任 签 字: 2012年 6月 22日

基于Android手机平台的音乐播放器

1.1 编写目的

现今社会生活紧张,而欣赏音乐是其中最好的舒缓压力的方式之一,本项目的目的是开发一个可以播放主流音乐文件格式的播放器,本设计 的实现的这主要功能是播放Mp3,Wav多种格式的音乐文件,并且能够控制播放,暂停,停止,上一曲,下一曲,音量调节,视觉外观,播放列表和歌曲文件的管理操作等多种播放控制功能,界面简明,操作简单。

本项目是一款基于Android手机平台的音乐播放器,使Android手机拥有个性的多媒体播放器,使手机显得更生动灵活化,与人们更为接近,让手机主人随时随地处于音乐视频的旋律之中。使人们的生活更加多样化。也使设计者更加熟练Android的技术和其它在市场上的特点

1.2 功能需求(用例图分析)

根据项目的目标,我们可获得项目系统的基本需求,以下从不同角度来描述系统的需求,并且使用用例图来描述,系统的功能需求,我们分成四部分来概括,即播放器的基本控制需要,播放列表管理需求,播放器友好性需求和播放器扩展卡需求。以下分别描述:

1.2.1 播放器的基本控制需求

音乐播放器的基本功能播放退出播放程序暂停停止进入播放清单上一首/下一首用户<>音量控制静音控制歌词显示播放文件

图1.1 播放器基本控制图

用例名称:播放 参与者:用户 目标:使得用户可以播放在播放列表中选中的歌曲 前置条件:播放器正在运行 基本事件流:1.用户单击“播放”按钮 2.播放器将播放列表中的当前的歌曲

用例名称:暂停 参与者:用户 目标:使得用户可以暂停正在播放的歌曲 前置条件:歌曲正在播放且未停止和暂停 基本事件流:1.用户单击“暂停”按钮 2.播放器将暂停当前的歌曲

用例名称:停止 参与者:用户 目标:使得用户可以停止正在播放的歌曲 前置条件:歌曲正在播放或暂停 基本事件流:1.用户单击“停止”按钮 2.播放器将停止当前播放的歌曲

用例名称:上一首/下一首 参与者:用户 目标:使得用户可以听上一首或下一首歌曲 前置条件:歌曲正在播放或暂停 基本事件流:1.用户单击“上一首或下一首”按钮 2.播放器将播放上一首或下一首歌曲

用例名称:播放清单 参与者:用户 目标:使得用户可以进入播放清单 前置条件:程序在运行 基本事件流:1.用户单击“清单”按钮 2.播放器进入清单列表

1.2.2 播放清单列表管理需求

当用户选中列表中某一项歌曲,就有的需求:

当用户选中某一首歌曲应有的菜单 歌曲列表播放详细加入铃声库用户增加移除全部移除设定

图1.2 播放器清单

用例名称:播放 参与者:用户 目标:使得程序播放选中的歌曲 前置条件:程序运行在播放菜单选项中 基本事件流:1.用户单击“播放”按钮 2.播放器进入播放状态

用例名称:详细

参与者:用户 目标:使得程序显示歌曲详情 前置条件:程序运行在播放菜单选项中 基本事件流:1.用户单击“详细”按钮 2.显示歌曲详细状态

用例名称:增加 参与者:用户 目标:使得程序进入手机扩展SD卡 前置条件:程序运行在播放菜单选项中 基本事件流:1.用户单击“增加”按钮 2.播放器进入手机扩展SD卡

用例名称:移除/全部移除 参与者:用户 目标:使选中的歌曲被移除 前置条件:程序运行在播放菜单选项中 基本事件流:1.用户单击“移除/全部移除”按钮 2.播放器移除选中歌曲/全部移除歌曲

用例名称:设定 参与者:用户 目标:使得程序进入播放器设定状态 前置条件:程序运行在播放菜单选项中 基本事件流:1.用户单击“设定”按钮 2.播放器进入设定界面

1.2.3 播放友好性需求

播放设定单曲循环顺序播放播放模式随机播放用户系统设定歌词显示歌词开启歌词关闭图1.3 播放器设定

用例名称:播放模式 参与者:用户 目标:使得程序进入播放模式设定状态 前置条件:程序运行在播放器设定界面中 基本事件流:1.用户单击“顺序、随机、单曲”按钮 2.播放器进入选中模式播放状态

用例名称:歌词显示 参与者:用户 目标:使得程序进入播放器歌词设置状态 前置条件:程序运行在播设定界面 基本事件流:1.用户单击“歌词开关按钮”按钮 2.播放器显示或关闭歌词

2.1 系统界面需求

播放器界面要求布局合理,颜色舒适,控制按钮友好 (图2.1)

图2.1 播放器界面

说明:左下角为清单按钮 右下角为程序退出按钮 蓝色条为音轨

2.2 系统性能需求

根据Android手机系统要求无响应时间为5秒,所以就有如下性能要求: (1)当要求歌曲播放时,程序响应时间最长不能超过5秒 (2)当要求歌曲暂停时,程序响应时间最长不能超过5秒 (3)当要求歌曲停止时,程序响应时间最长不能超过5秒 (4)当要求歌曲上/下一首时,程序响应时间最长不能超过5秒 (5)当要求进行清单列表时,程序响应时间最长不能超过5秒

3.1 数据库连接

这里将介绍如何进行Android数据库连接,Android中自带SQLite数据库,这是一个十分小型的数据库,这样正适合Android这种移动平台使用。

Android数据库存储的位置在data/data/<项目文件夹>/databases/目录下 Android是利用ContentProvider作为内容提供商,SQLiteOpenHelper数据库帮助类来进行对数据库的创建和操作。通过Context.getContentResolver()方法直接对数据库进行操作。程序中数据库类为DBHelper extends SQLiteOpenHelper(继承关系),内容提供类DBProvider extends ContentProvider(继承关系)

3.1.1 创建数据库

Android 提供了标准的数据库创建方式。继承SQLiteOpenHelper ,实现onCreate 和 onUpgrade 两个方法,有个好处就是便于数据库版本的升级,连接数据库的算法如下:

public DBHelper(Context context) {// 创建数据库

}

super(context, DATABASE_NAME,null, DATABASE_VERSION);

public void onCreate(SQLiteDatabase db) {// 创建时调用 db.execSQL(DATABASE_CREATE); }

public void onUpgrade(SQLiteDatabase db, int oldVersion, int

newVersion) {// 版本更新时调用

db.execSQL(\onCreate(db);

}

@Override // 在ContextProvider运行时自动创建数据库

public boolean onCreate() {

dbOpenHelper= new DBHelper(getContext());

return true;

}

数据库如果创建不成功则抛出FIleNotFoundException异常 3.1.2 操作数据库

Android对数据库的操作主要有插入、删除、更新、查询操作,在进行任何操作时都必须指定一个Uri,才能对相应的表进行数据操作。

//数据库删除操作

@Override

public int delete(Uri arg0, String arg1, String[] arg2) {

SQLiteDatabase db = dbOpenHelper.getWritableDatabase(); try {

Db.delete(FileColumn.TABLE, arg1, arg2);

}

} catch (Exception ex) {

ex.printStackTrace();

}return 1;

@Override//数据库插入操作

public Uri insert(Uri uri, ContentValues values) {

SQLiteDatabase db = dbOpenHelper.getWritableDatabase(); long count = 0;

try { count = db.insert(FileColumn.TABLE, null, values); } catch (Exception ex) { ex.printStackTrace(); }

}

// 数据库更新操作

@Override

public int update(Uri uri, ContentValues values, String selection,String[]

if (count > 0) return uri; else return null;

selectionArgs) {

}

3.1.3 数据显示

程序是利用Cursor游标类指向数据表中的某一项,然后进行查询数据,用Log日志显示出来

@Override//数据库查询操作

public Cursor query(Uri uri, String[] projection, String selection,String[]

SQLiteDatabase db = dbOpenHelper.getWritableDatabase(); int i = 0; try {

i = db.update(FileColumn.TABLE, values, selection, null);return i;

} catch (Exception ex) {} return 0;

selectionArgs, String sortOrder) {

SQLiteDatabase db = dbOpenHelper.getWritableDatabase();

图 4.4 图 4.5 图 4.6 图 4.7

4.2.2AndroidManifest.xml文件

Android系统的任何一个程序启动都需要AndroidManifest.xml来启动程序,任何一个新建的工程目录都会自动生成一个AndroidManifest.xml文件,此配置文件是整个程序能够正常运行的核心,它里面包含了Android SDK的版本,程序运行的默认Activity,当程序中的任何一个组件触发事件后,系统都会自动的去AndroidManifest.xml中寻找标识来作出相应的操作。任何一个AndroidManifest.Xml文件的格式都应为:

Android系统有一个编码的规定,支持的编码是\,当程序中出现乱码是,我们须将其编码格式转化为\在 AndroidManifest.xml中会在第一行声明一句:

xmlns:android=\

xmlns(XML namespace)是一个命名空间,它就像一条河的源头一样能让我们找到系统架构,每一个配置文件必须有这个xmlns,否则程序中的所使用的所有资源将无法找到。 在application元素我们定义android:icon=\

android:label=\,android:icon是程序在手机中显示的图片,我们运用@drawable/icon表示了对res/drawable目录下的icon.png的引用。@string/app_name表示了对res/value目录下string.Xml中定义的app_name参数的引用。

这是系统确定的首先要启动的Activity是PlayRackActivity。

在intent-filter选项中,有action和category等等属性,我们需要定义action的值为android.intent.action.MAIN,category的值为android.intent.category.LAUNCHER,它们是系统的值,程序在解析到这些常用后就可以确定首先要启动的Activity。当我们需要通过一个组件触发另一个组件时,我们将设定action和category的其它属性值,系统会根据我们设定的属性值去AndroidManifest.Xml的application 中寻找标识,任何一个Activity的action和category是唯一,所以程序在任何时候都能唯一启动一个Activity,这样,不同的Activity之间的跳转就实现了。

在AndroidManifest.Xml中有一个根结点,它是我们需要定义的ADT版本,例如我们将其值设定为android:minSdkVersion=\,则表示此Android工程所用的版本为1.6,Android还有1.1、1.5、1.6、2.0、2.1这几个版本。

如果我们需要对网络进行访问,比如打开一个网页,刚我还需要设置一个网络访问权限uses-permission,将其的值设置为android:name=\,我们就可以访问网络了。当然uses-permission还有很多其它的权限,例如GPS定位权限,浏览器数据存取权限com.android.browser.permission.READ_HISTORY_BOOKMARKS等等。

当程序的任何一个组件要用到时,都必须在AndroidManifest.Xml文件中声明。四大组件要使用前都需要声明,其声明方式如下:

其中声明provider时还需要声明其授权 authorities。每个组件里面还有很多的属性,会根据程序的具体需要定义不同的属性。过滤器intent-filter 有两种启动方式来启动界面: (1) 显示方式

显示方式是在代码中的直接启动组件,启动时会声明Intent,在它的构造方法Intent(组件1,组件2)中直接指定一个组件的名字,然后调用方法startIntent(intent)以启动指定的组件。 (2) 隐式方式

隐式方式是通过过滤器来过滤完成的,启动的组件必须满足action和category的条件才能够启动该组件。这些属性是在AndroidManifest.Xml文件中声明的。两种启动方式都可以通过程序setAction(ACTION常量)和startActivity(intent)或配置文件两种方式来

实现组件的跳转。

播放器系统功能详细设计

5.1音乐播放器主界面功能实现

5.1.1 播放器主界面

播放器主界面(图5.1)

图 5.1

Android的每一个可视化界面,都有其的唯一的布局配置文件,该文件里面有各种布局方式,和各种资源文件如图像,文字,颜色的引用,程序在运行时,可以通过代码对各配置文件进行读取。这样就可以形成不同的可视化界面和炫丽的效果。播放器主界面是一个Activity,Android工程在每个activity启动的时候会首先执行Oncreate()方法,如下代码:

@Override

Public void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.play_rack);}

该方法主要执行界面的初始化操作,Activity有个设置布局的方法:Context.setContentView(layoutResID),参数为资源ID,该Id在工程目录res/layout下,主界面布局文件名为play_rack。

下面为play_rack.xml布局文件代码结构如下:

在绝对布局下嵌套两种线性布局,第一个实现了标题和歌曲名的显示位置,通过布局设置绝对坐标来控制标题的位置。每个布局内可以放置多种Widget(窗体部件)例如:等。每个Widget内有多种属性,可以设置该Widget的坐标,大小,背景和颜色等参数。在播放界面中,歌词显示为居中,实现方法代码如下:

android:gravity=\

android:layout_width=\

android:textColor=\android:layout_width=\

属性:

orientation=\:此线性布局的子部件为水平方式布局

Layout_width=\:布局的宽度为填满父布局

Layout_height=\:布局的高度子由窗体的大小决定

窗体TextView 文本 :textColor=\设置文本显示的颜色RGB为 \

TextSize为默认大小

5.1.2 播放界面音轨的实现

播放器音轨SeekBar(如下图)

Android系统自带SeekBar(如下图)

图 5.2

不管是从界面外观还是从功能上,系统自带的SeekBar往往不能满足用户的需要。所以

我在这里自定义了一个音轨SeekBar,

在play_rack.Xml配置文件中,SeekBar的代码如下:

android:layout_height=\

android:layout_y=\

android:progressDrawable=\

android:thumb=\

android:paddingLeft=\

android:paddingRight=\android:progress=\

android:max=\

上面代码中有参数android:thumb=\为音轨游标的图片资源android:progressDrawable=\为SeekBar条的风格style。引用了drawable中的seekbay_style.xml文件,seekbay_style.Xml是自定义的配置文件,算法如下:

android:endColor=\

android:endColor=\

android:centerY=\/>

配置文件中三个Item项依次决定了SeekBar的三层背景,从最下层的灰色到最上层的蓝色。通过各种属性设置了SeekBar的倾斜度,两端圆半径,角度,中心位置,起始,中心和

结束的颜色,游标的起始位置。通过这些属性设置,就自定义一个如上图一的SeekBar音轨.

播放器最重要的一部分就是音轨与歌曲进度同步的实现。音轨设置了两个TextView用来显示当前歌曲播放的进度时间和歌曲的长度(图5.3)

图 5.3

音轨对象SeekBar在歌曲刚开始播放的时候调用方法SeekBar.setMax(),参数传入歌曲的长度。SeekBar.setProgress(1)设置游标的起始进度为1。然后程序运行如下代码:

private Runnable thread_One = new Runnable() {// 线程

public void run() {

int currently_Progress = seekBar.getProgress() + 1000; seekBar.setProgress(currently_Progress);

currently_Time.setText(getFileTime(mplayer.getCurrentPosit ion()));

showLrcTwo(lrc_time, lrc_word);handler.postDelayed(thread_One, 1000);}}; Android的线程的开始是通过Handler类来进行的,Handler类是线程与线程之间通信的

桥梁,实现Runnable接口会实现里面的run方法,当线程开始的时候,Runnable中的run方法会向Handler发一个Message消息,这样,Handler类就可以接收到run方法发送过来的不同的消息进行不同的代码处理。这样就达到了各线程之间的通信。要启动一个线程调用Handler的方法postDelayed(Runnable,1000)表示线程睡眠时间是1000ms 。

以上代码意思是让播放歌曲的线程每隔1000ms,即每1秒对音轨的TextView重新设置时间且让进度条前进1秒的进度。对音轨进行刷新。这样就实现了歌词同步功能SeekBar有一个监听器,该监听器的作用是一直保持着对进度条的监听,当我们用鼠标向SeekBar的各位置进行点击时,它会自动监听其位置,进行相应的位置显示。这也是进度条上的游标会不停的移动和歌词时间会不停的变动的原因。

5.1.3 播放器播放、暂停、停止等功能

图 5.4

如图5.4所示:各按钮水平放置,用的是布局中的线性布局LinearLayout,用方法setOrientation(horizontal);将其设置为水平。LinearLayout中依次放置播放,暂停,停止,上、下一曲按钮属性。配置文件代码结构如下:

android的媒体播放原理:android源程序已经为我们封装好了一个接口类,叫MediaPlayer。该接口在执行行需要一个数据源,通过如下四个步骤:

第一步:MediaPlayer.reset();复位操作,为以后的媒体准备播放作准备。 第二步:传入歌曲数据源,这里也是一个数据流

MediaPlayer.setDataSource(String path);参数需要传一个路径,该接口类在收到路径后将其转化为数据源。

第三步:准备播放数据源,调用方法MediaPlayer.Prepare();

第四步:MediaPlayer.Start();播放数据源,该数据源播放后,不再与程序 有关,需要用MediaPlayer.Stop()方法让其停止或MediaPlayer.Start();让其启动;

歌曲数据源的获得:要获得数据源,需要我们提供给接口类一个歌曲存放路径,而这个路径已经被事先放到数据库里了,我们只需要进行数据库进行操作。将里面的路径取出。这里将调用PlayRackActivity的一个方法query();代码算法如下:

public String query() {

ContentResolver cr = getContentResolver(); Uri uri = DBProvider.CONTENT_URI; String[] projection = { \ String selection = \

String[] selectionArgs = { selectName };

Cursor c=cr.query(uri,projection,selection, selectionArgs, null);

if (c.moveToFirst()) {

String path = c.getString(0); return path; }return null; }

方法getContentResolver是包android.content.ContextWrapper里面的方法,它会自动的调用ContentProvider中的关联数据库,我们需用这个方法就可以操作数据库。数据库操作需要一个Uri 。Uri类似一个网络连接的Url。Uri是数据库唯一的标识,不同的Uri可以操作不同的数据库表。在查询数据库时需要传入一个当前播放的歌曲名字,通过歌曲名字来查询歌曲的路径。

5.2 播放列表功能

播放列表界面(如图5.5)

图 5.5

布局层次关系如下:

在Android里面,有一个视图叫ListView,其特点是一个有BaseAdapter的属性,从下到下,或从左到右的显示方式。系统默认的方式每一行只显示一个TextView,本播放列表实现了自定义的方式,刚ListView的每一行显示一个音乐图片和一个歌曲名字。我们定义一个类MusicAdapter 继承了BaseAdapter,然后通过算法对这个适配器进行扩展,扩展成为第一行能显示一张图片和一个歌曲名字。由于BaseAdapter是一个抽象类,我们需要实现里面的抽象方法getView()。该方法返回一个View,即视图。视图可以显示在Activity上,所以就可以看到我们想要的歌曲列表界面。

ListView同样有一个监听器new onItemClickListener(){

@Override public void onItemClick(AdapterView arg0, View arg1, int arg2,long arg3) {}},我们只要实现这个方法,就可以监听鼠标的点击事件,当鼠标点击到每一行时,可以通过ListView.getItemAtPositon(int position)得到该行上的信息。这样就可以通过

Intent将数据传入到其它的Activity。本程序的思路是当鼠标点击一行,会跳转到另一个Activity里面,这个Activity和歌曲列表类似,也是一个ListView,该界面将在下一节介绍。

歌曲列表是从播放主界面跳转过来的,能跳到该歌曲列表是前提是数据有歌曲列表的

存在。因为每次歌曲列表显示时会查询数据库中的歌曲列表。如果不存在刚会提示是空列表,选择到SDCard中添加歌曲(如图5.6)

图 5.6

中间为一个Dialog对话框,具有Acitivty的属性,但是独立于界面的一个视图,该对话框中放置了一个布局文件。

Dialog的创建:AlertDialog.Builder,AlertDialog alert =builder.create();alert.show();

该 Dialog上有两个菜单选项,第一个为“从SD卡”,点击会跳转到SDcard界面中。

5.3 菜单功能

菜单界面(如图5.7)

图 5.7

5.3.1 菜单界面

在Menu.Xml配置文件中,布局结构如下:

在程序中的Menu.Java中有List容器,该容器可以存放String类型的字符,如下:

List seclect_items = new ArrayList();

seclect_items.add(\播放\

seclect_items.add(\详细\seclect_items.add(\新增\seclect_items.add(\移除\seclect_items.add(\全部移除\seclect_items.add(\设置\

然后通过ListView.setAdapter();方法将这些参数设置到界面中去,可以看到与界面显示效果相同!

该菜单每一行有一张图片和一个菜单选项(如图5.8)

图 5.8

ListAdapter继承一个BaseAdapter,实现里面的getView()方法,再对其进行扩展。 View getView(int position, View convertView, ViewGroup parent) {

convertView = inflater.inflate(R.layout.file_row, null);holder.text =

(TextView) convertView.findViewById(R.id.text);holder.icon = (ImageView) convertView.findViewById(R.id.image_Icon); }

convertView.setTag(holder);

本文来源:https://www.bwwdw.com/article/ghig.html

Top