基于安卓的音乐播放器需求分析说明书.docx
《基于安卓的音乐播放器需求分析说明书.docx》由会员分享,可在线阅读,更多相关《基于安卓的音乐播放器需求分析说明书.docx(19页珍藏版)》请在冰豆网上搜索。
![基于安卓的音乐播放器需求分析说明书.docx](https://file1.bdocx.com/fileroot1/2022-12/1/3d121a4e-222c-435d-8f53-93bfd1bce3ea/3d121a4e-222c-435d-8f53-93bfd1bce3ea1.gif)
基于安卓的音乐播放器需求分析说明书
卷号
卷内编号
密级
项目编号:
Boom!
音乐播放器
需求分析说明书
项目承担部门:
2012管工班第三组
完成日期:
2015.09.04
本文档使用部门:
评审负责人(签名):
评审日期:
1.简介
1.1目的
本文档用于描述音乐播放器APP的总体架构,用于指导各app的具体实施。
本文档的用户包括系统设计师、开发人员、测试人员、评审组成员。
1.2范围
此说明书适用于音乐播放器app项目。
1.3APP参与者
手机用户
2.构架表示方式
3.构架目标和约束
✓主要建设功能:
导入本地歌曲文件、选择显示歌词、更换皮肤、在线试听、在线下载(资源在服务器上)、选择显示歌手简介、选择显示专辑简介、选择推荐专辑内其他本地没有的歌曲、显示乐库歌曲排行榜、新建歌单、管理歌单等功能。
✓交互设计:
提供良好的交互设计、操作简单快速、按钮及菜单设计合理,合理引导用户使用。
✓完善的日志,所有操作数据库记录日志。
✓个性化:
提供完全个性化的播放平台,为不同用户定制符合其喜好的歌曲及歌单,为其提供不同的主题样式、播放模式、播放菜单。
✓用户记忆:
提供记住用户名及记住密码功能,用户可选择记忆期限:
周、月、半年、年、或永远。
✓app能够承受一次下载同事下载5首歌曲、在播放同时下载的并发压力。
✓各界面色彩基调相似。
操作习惯、风格相似。
4.APP用例
歌曲界面控制可分为:
播放/暂停/停止模块、上一曲/下一曲
模块、音量模块。
4.1播放/暂停/停止模块
流程图:
NN
YY
N
Y
程序逻辑:
当用户点击播放\暂停\停止按钮时,播放器就对当前播放事
件监听从而控制当前音乐的播放\暂停\停止,部分关键代码如下:
//播放按钮
playPauseBtn.setOnClickListener(newOnClickListener(){
publicvoidonClick(Viewv){
intcmd=0;
Intenti=newIntent(MusicService.MUSIC_CONTROL);
//判断当前的状态值是什么状态如果是播放状态
if(status==MusicService.STATUS_PLAYING){
cmd=MusicService.CMD_PAUSE;//发送暂停的命令
}elseif(status==MusicService.STATUS_STOPPED){
cmd=MusicService.CMD_START;//发送播放的命令
}else{
cmd=MusicService.CMD_RESUME;//继续播放的命令
}
i.putExtra("cmd",cmd);//将命令广播出去
sendBroadcast(i);//发送广播
}});
4.2上一曲\下一曲模块
流程图:
NN
YY
程序逻辑:
当用户点击上一曲\下一曲按钮时,播放器就对当前播放事
件监听,从音乐列表中转换音乐,从而控制当前音乐的上一曲\
下一曲,关键代码如下:
//上一曲键事件监听器
previousBtn.setOnClickListener(newOnClickListener(){
publicvoidonClick(Viewv){
Intenti=newIntent(MusicService.MUSIC_CONTROL);
intcmd=MusicService.CMD_PREV;//发送前一首的命令
i.putExtra("cmd",cmd);sendBroadcast(i);
}
});
//下一曲键事件监听器
nextBtn.setOnClickListener(newOnClickListener(){
publicvoidonClick(Viewv){
Intenti=newIntent(MusicService.MUSIC_CONTROL);
intcmd=MusicService.CMD_NEXT;
i.putExtra("cmd",cmd);
sendBroadcast(i);
}
});
//设置SeekBar的监听事件
sb.setOnSeekBarChangeListener(newOnSeekBarChangeListener()
{//当停止拖动时调用的方法
publicvoidonStopTrackingTouch(SeekBarseekBar){}
publicvoidonStartTrackingTouch(SeekBarseekBar){}
//当SeekBar拖动时会执行此方法
publicvoidonProgressChanged(SeekBarseekBar,intprog,
booleanfromUser){
//fromUser参数意思是判断拖动是否是用户用手拖动的
if(fromUser==true&&Math.abs(prog-progress)>=5){
progress=prog;
Intenti=newIntent(MusicService.MUSIC_CONTROL);
intcmd=MusicService.CMD_SEEK;//发送拖动的命令
i.putExtra("cmd",cmd);
i.putExtra("progress",progress);//讲拖动的进度传进Service
sendBroadcast(i);
sb.setProgress(progress);
}
}
});
}
4.3音量模块
流程图:
N
Y
Y
N
Y
N
程序逻辑:
声音有两个按钮控制,一个增加声音和一个减少声音。
通过
这两个按钮用户可以调节播放音乐的声音大小,用AudioManager
组件对声音的大小进行增减,最大为7,最小为0。
当用户点击
声音按钮时,若是增按钮,对声音进行增加,若是减按钮对声音
进行减小。
部分代码如下:
//获取点击事件
voiceUp=(ImageButton)findViewById(R.id.music_voic_up);
//音量增加
voiceDown(ImageButton)findViewById(R.id.music_voic_down);
//音量增减小执行事件
audiomanage=(AudioManager)getSystemService(
Context.AUDIO_SERVICE);
voiceDown.setOnClickListener(newOnClickListener(){
publicvoidonClick(Viewv){
audiomanage.adjustVolume(
AudioManager.ADJUST_LOWER,0);
Volume=audiomanage.getStreamVolume(
AudioManager.STREAM_RING);
if(volume>0){
volume--;
audiomanage.setRingerMode(volume);
}
}
});
//声音控制按钮声音增加
voiceUp.setOnClickListener(newOnClickListener(){
publicvoidonClick(Viewv){
audiomanage.adjustVolume(AudioManager.ADJUST_RAISE,0);
volume=audiomanage.getStreamVolume(
AudioManager.STREAM_RING);
if(volume<7){
volume++;
audiomanage.setRingerMode(volume);
}
}
});
5.层次结构
6.逻辑视图
系统采用J2EE技术,基于Liferay4.2.2开源门户框架进行开发,具体开发环境如下:
ØJDK:
1.7
Ø开发工具:
Eclipse10、MyEclipse10
Ø应用服务器:
Tomcat8.0
Ø数据库服务器:
MySQL5.6
Ø版本控制:
TortoiseSVN
Ø项目管理工具:
MicrosoftProject2000
7.进程视图
8.部署视图
本项目使用SQLiteDatabase安卓内置数据库。
数据库名称:
musicstore_new
表music_info
Name
Field
PrimaryKey
Canitbeempty?
Notes
_id
integer
y
n
主键
songid
integer
n
y
albumid
Integer
n
y
duration
integer
n
y
musicname
varchar(10)
n
y
artist
char
n
y
data
char
n
y
folder
char
n
y
musicnamekey
char
n
y
artistkey
char
n
y
favorite
integer
n
y
创建表语句
privatestaticfinalStringTABLE_MUSIC="music_info";
db.execSQL("createtable"
+TABLE_MUSIC
+"(_idINTEGERPRIMARYKEYAUTOINCREMENT,"
+"songidinteger,albumidinteger,durationinteger,musicnamevarchar(10),"
+"artistchar,datachar,folderchar,musicnamekeychar,artistkeychar,favoriteinteger)");"
表album_info
Name
Field
PrimaryKey
Canitbeempty?
Note
_id
integer
y
n
album_name
char
n
y
album_id
char
n
y
album_art
char
n
y
创建表语句
privatestaticfinalStringTABLE_ALBUM="album_info";
"createtable"
+TABLE_ALBUM
+"(_idINTEGERPRIMARYKEYAUTOINCREMENT,"
+"album_namechar,album_idinteger,number_of_songsinteger,album_artchar)"
createtable"
+TABLE_ARTIST
+"(_idINTEGERPRIMARYKEYAUTOINCREMENT,artist_namechar,number_of_tracksinteger)"
表folder_info
Name
Field
PrimaryKey
Canitbeempty?
Note
_id
integer
y
N
folder_name
char
n
y
folder_path
char
n
Y
创建表语句
privatestaticfinalStringTABLE_FOLDER="folder_info"
createtable"
+TABLE_FOLDER
+"(_idINTEGERPRIMARYKEYAUTOINCREMENT,folder_namechar,folder_pathchar)"
表favorite_info
Name
Field
PrimaryKey
Canitbeempty?
Note
_id
integer
y
n
songid
integer
n
y
albumid
integer
n
y
duration
integer
n
y
musicname
Varchar(10)
n
y
artist
char
n
y
data
char
n
y
folder
char
n
y
musicnamekey
char
n
y
artistkey
char
n
y
favorite
integer
n
y
创建表语句
privatestaticfinalStringTABLE_FAVORITE="favorite_info";
createtable"
+TABLE_FAVORITE
+"(_idinteger,"
+"songidinteger,albumidinteger,durationinteger,musicnamevarchar(10),"
+"artistchar,datachar,folderchar,musicnamekeychar,artistkeychar,favoriteinteger)"
数据库更新语句
publicvoidonUpgrade(SQLiteDatabasedb,intoldVersion,intnewVersion){
if(newVersion>oldVersion){
db.execSQL("DROPTABLEIFEXISTS"+TABLE_ARTIST);
db.execSQL("DROPTABLEIFEXISTS"+TABLE_ALBUM);
db.execSQL("DROPTABLEIFEXISTS"+TABLE_MUSIC);
db.execSQL("DROPTABLEIFEXISTS"+TABLE_FOLDER);
onCreate(db);
}
}
数据库删除语句
publicvoiddeleteTables(Contextcontext){
SQLiteDatabasedb=this.getWritableDatabase();
db.delete(TABLE_ALBUM,null,null);
db.delete(TABLE_ARTIST,null,null);
db.delete(TABLE_FAVORITE,null,null);
db.delete(TABLE_FOLDER,null,null);
db.delete(TABLE_MUSIC,null,null);
}
添加数据到album_info表
publicvoidsaveAlbumInfo(Listlist){
SQLiteDatabasedb=DatabaseHelper.getInstance(mContext);
for(AlbumInfoinfo:
list){
ContentValuescv=newContentValues();
cv.put("album_name",info.album_name);
cv.put("album_id",info.album_id);
cv.put("number_of_songs",info.number_of_songs);
cv.put("album_art",info.album_art);
db.insert(TABLE_ALBUM,null,cv);
}
}
获取数据从album_info表
publicListgetAlbumInfo(){
SQLiteDatabasedb=DatabaseHelper.getInstance(mContext);
Listlist=newArrayList();
Stringsql="select*from"+TABLE_ALBUM;
Cursorcursor=db.rawQuery(sql,null);
while(cursor.moveToNext()){
AlbumInfoinfo=newAlbumInfo();
info.album_name=cursor.getString(cursor.getColumnIndex("album_name"));
info.album_art=cursor.getString(cursor.getColumnIndex("album_art"));
info.album_id=cursor.getInt(cursor.getColumnIndex("album_id"));
info.number_of_songs=cursor.getInt(cursor.getColumnIndex("number_of_songs"));
list.add(info);
}
cursor.close();
returnlist;
}
判断数据表是否有数据
publicbooleanhasData(){
SQLiteDatabasedb=DatabaseHelper.getInstance(mContext);
Stringsql="selectcount(*)from"+TABLE_ALBUM;
Cursorcursor=db.rawQuery(sql,null);
booleanhas=false;
if(cursor.moveToFirst()){
intcount=cursor.getInt(0);
if(count>0){
has=true;
}
}
cursor.close();
returnhas;
}
获取数据表的记录数
publicintgetDataCount(){
SQLiteDatabasedb=DatabaseHelper.getInstance(mContext);
Stringsql="selectcount(*)from"+TABLE_ALBUM;
Cursorcursor=db.rawQuery(sql,null);
intcount=0;
if(cursor.moveToFirst()){
count=cursor.getInt(0);
}
returncount;
}
}
9.数据视图
所有对数据的写操作均记录系统日志,通过拦截LiferayServiceBuilder生成的数据操纵类的相关方法实现,具体用其ModelListener机制来实现;
各个功能模块根据规则控制数据范围和读写权限。
一般根据组织机构控制数据范围,根据角色控制读写权限。
10.大小和性能
随着用户访问数量的变化,可以通过负载均衡的方式提供更大的并发访问,示意图如下所示:
11.质量
系统运行稳定,基本功能全部实现。