电子科技大学成都学院云计算系
实践专周设计报告
课 程 名 称: 基于android的音乐应用
设 计 题 目:_基于android的音乐播放器开发
指导 教师 组: 陈虹君
学生姓名学号:
云计算系制
20##年12月
目 录
实践专周设计报告........................................................................................................... 1
第1章 引言................................................................................................................. 1
1.1 问题分析.................................................................................................................... 1
1.2 设计目标.................................................................................................................... 1
1.2.1 基本功能................................................................................................................. 1
1.2.2 扩展功能................................................................................................................. 2
1.3 研究思路.................................................................................................................... 2
第2章 总体设计......................................................................................................... 3
2.1 程序功能结构图........................................................................................................ 3
2.2 程序的功能分析........................................................................................................ 3
第3章 详细设计......................................................................................................... 4
3.1 数据库分析与设计.................................................................................................... 4
3.2 模块功能.................................................................................................................... 4
3.2.1 列表显示模块......................................................................................................... 4
3.2.2 音乐播放模块......................................................................................................... 4
3.2.3 歌词显示模块......................................................................................................... 5
3.2.4 后台播放模块......................................................................................................... 5
第4章 系统实现......................................................................................................... 6
4.1 播放器加载界面..................................................................................................... 6
4.2 音乐列表显示......................................................................................................... 7
4.3 歌曲扫描界面......................................................................................................... 9
4.4 音乐播放界面....................................................................................................... 11
4.5 歌词滚动显示....................................................................................................... 18
4.6 Appwidget.............................................................................................................. 20
4.7 通知栏界面........................................................................................................... 23
第5章 测试和总结................................................................................................... 26
5.1 系统存在的问题及解决方案.................................................................................. 26
5.2 收获与心得.............................................................................................................. 26
参考文献......................................................................................................................... 27
致谢................................................................................................................................. 28
第1章 引言
1.1 问题分析
如何实现歌词显示:歌词应该使用自定义的TextView来显示,还需要对歌词进行解析。
如何设计各个activity与service的数据交换:用Intent交换传递,并设计数据交换模型。
1.2 设计目标
设计一个拥有音乐播放列表、歌词页面,播放页面,并能后台播放,能快进,快退,下一曲,上一曲,循环播放的音乐播放器
1.2.1 基本功能
拥有音乐播放列表,音乐播放界面,可以快进,快退,上一曲,下一曲,设置循环播放类型,歌词显示,播放进度显示。本程序的功能模块图如图1-1所示。
图1-1 android音乐播放器功能模块图
1.2.2 扩展功能
(1) 歌词两种显示方式,一种两行显示,一种滚动显示。
(2) 使用数据库保存音乐信息,查找音乐效率高。
(3) 可以设置循环播放模式。
(4) 通知栏显示歌曲名称和歌手名。
(5) 拥有appwidget,并可以控制音乐播放。
1.3 研究思路
一、首先用xml文件设计布局,制作各种图片。
二、编写各种功能类,比如文件扫描,歌词解析等等。
三、详细编写逻辑代码,调用各个功能类。
四、调试运行,查错,优化。
第2章 总体设计
2.1 程序功能结构图
图2-1 程序功能结构图
2.2 程序的功能分析
拥有音乐播放列表,音乐播放界面,可以快进,快退,上一曲,下一曲,设置循环播放类型,歌词显示,播放进度显示。
第3章 详细设计
3.1 数据库分析与设计
数据库分析:
一、歌曲信息表;
数据库设计:
表3-1歌曲信息表
3.2 模块功能
3.2.1 列表显示模块
使用android提供的list类实现歌曲列表显示,从数据库中查询歌曲信息使用adapter显示到列表中,点击列表选项后将数据传至service进行音乐播放。
3.2.2 音乐播放模块
接收从播放列表传来得数据,并显示到播放页面,通过界面按钮控制service播放音乐播放进度,下一曲等。
3.2.3 歌词显示模块
自定义一个TextView来显示歌词,编写歌词解析类,并存入数组供歌词显示类使用。
3.2.4 后台播放模块
使用service实现后台播放,程序加载时将歌曲信息传入service,当接收到播放命令时执行音乐播放及发送广播等操作。
第4章 系统实现
4.1 播放器加载界面
主界面运行效果如图4-1所示。
图4-1 加载界面效果
本图分为程序加载页面,后台实现启动service,读取数据库等操作,为音乐播放做准备。
4.2 音乐列表显示
音乐列表显示界面运行效果如图4-2所示。
图4-2 音乐列表显示界面运行效果
本界面为音乐列表界面,点击音乐即可播放音乐并跳转到音乐播放页面。
核心代码如下:
public void listload(){
lv=(ListView) findViewById(R.id.mm_lv1);
Cursor c=db.rawQuery("select _id, title , singer from menu", null);
startManagingCursor(c);
mAdapter=new Listadapter(Musicmenu_do.this, c);
lv.setAdapter(mAdapter);
ItemClickListener ItemClickListener=new ItemClickListener();
lv.setOnItemClickListener(ItemClickListener);
if(position!=-1){
lv.setSelection(position);
mAdapter.setpic(position);
mAdapter.notifyDataSetChanged();
}
}
public class ItemClickListener implements AdapterView.OnItemClickListener{
@Override
public void onItemClick(AdapterView<?> arg0, View arg1, int arg2,
long arg3) {
// TODO 自动生成的方法存根
String msg="playmusic";
Intent intent1=new Intent(Musicmenu_do.this,Music_service.class);
intent1.putExtra("position", arg2);
intent1.putExtra("msg", msg);
startService(intent1);
Intent intent2=new Intent(Musicmenu_do.this,Musicplay_do.class);
startActivity(intent2);
curriv = (ImageView) arg1.findViewById(R.id.mm_iv);
curriv.setBackgroundResource(R.drawable.listplay);
}
}
4.3 歌曲扫描界面
歌曲扫描界面运行效果如图4-3所示。
图4-3 歌曲扫描界面运行效果
本界面为音乐扫描界面,扫描完成后点击完成按钮返回列表页面并更新列表。
核心代码如下:
public class progress implements Runnable{
int n = 0;
int max;
public void run() {
db.delete("menu", null, null);
ContentResolver contentresolver=getContentResolver();
Cursor c=contentresolver.query(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, null, null, null, null);
max = c.getCount();
max = max>0?max:1;
if(c==null||!c.moveToFirst()){
Toast.makeText(Musicmenu_do.this, "SD卡中没有歌曲", Toast.LENGTH_SHORT).show();
}else{
int idColumn=c.getColumnIndexOrThrow(BaseColumns._ID);
int titleColumn=c.getColumnIndexOrThrow(MediaColumns.TITLE);
int albumColumn=c.getColumnIndexOrThrow(AudioColumns.ALBUM);
int singerColumn=c.getColumnIndexOrThrow(AudioColumns.ARTIST);
int dataColumn=c.getColumnIndexOrThrow(MediaColumns.DATA);
int durationColumn=c.getColumnIndexOrThrow(AudioColumns.DURATION);
int sizeColumn=c.getColumnIndexOrThrow(MediaColumns.SIZE);
do{
++n;
int id=c.getInt(idColumn);
String album=c.getString(albumColumn);
title1=c.getString(titleColumn);
String singer=c.getString(singerColumn);
String data=c.getString(dataColumn);
int duration=c.getInt(durationColumn);
int size=c.getInt(sizeColumn);
db.execSQL("insert into menu values(null,?,?,?,?,?,?,?)",new Object[]{id,title1,album,singer,data,duration,size});
Message msg = new Message();
msg.arg1 = max;
msg.arg2 = n;
msg.what =1;
handler.sendMessage(msg);
}while(c.moveToNext());
Message msg = new Message();
msg.arg2 = n;
msg.what =2;
handler.sendMessage(msg);
}
}
}
4.4 音乐播放界面
音乐播放界面运行效果如图4-4所示。
图4-4 音乐播放界面运行效果图
本界面是音乐播放界面,用户可以点击上面的按钮对音乐播放进行控制,同时两行歌词也显示在这一目录,向右滑动可进入歌词滚动显示页面。
核心代码如下:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="@drawable/bg" >
<android.support.v4.view.ViewPager
android:id="@+id/mp_vp"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_above="@+id/mp_tv_title" />
<LinearLayout
android:id="@+id/mp_ll2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_marginBottom="10dp"
android:gravity="center"
android:orientation="horizontal" >
<Button
android:id="@+id/mp_bt_up"
android:layout_width="85dp"
android:layout_height="85dp"
android:background="@drawable/bt_up_press" />
<Button
android:id="@+id/mp_bt_play"
android:layout_width="85dp"
android:layout_height="85dp"
android:layout_marginLeft="10dp" />
<Button
android:id="@+id/mp_bt_next"
android:layout_width="85dp"
android:layout_height="85dp"
android:layout_marginLeft="10dp"
android:background="@drawable/bt_next_press" />
</LinearLayout>
<TextView
android:id="@+id/mp_tv_title"
android:textSize="20sp"
android:textColor="#06aff6"
android:ellipsize="marquee"
android:singleLine="true"
android:layout_width="276dip"
android:layout_height="40dip"
android:background="#bbffffff"
android:layout_above="@id/mp_ll2"
android:gravity="center"
android:layout_centerInParent="true"
android:layout_marginBottom="10dp" />
</RelativeLayout>
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/mp_rl1"
android:layout_width="fill_parent"
android:layout_height="wrap_content" >
<RelativeLayout
android:id="@+id/mp1_rl1"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_marginTop="14dp"
android:gravity="center_horizontal" >
<ImageView
android:id="@+id/mp1_iv1"
android:layout_width="180dp"
android:layout_height="180dp"
android:layout_marginTop="10dp"
android:src="@drawable/musicicn" />
<LinearLayout
android:id="@+id/mp1_ll1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:layout_marginTop="10dp"
android:layout_toRightOf="@id/mp1_iv1"
android:orientation="vertical" >
<Button
android:id="@+id/mp1_bt_circle"
android:layout_width="85dp"
android:layout_height="85dp"
android:background="@drawable/bt_circle1_press" />
<Button
android:id="@+id/mp1_bt_menu"
android:layout_width="85dp"
android:layout_height="85dp"
android:layout_marginTop="10dp"
android:background="@drawable/bt_meau_press" />
</LinearLayout>
</RelativeLayout>
<SeekBar
android:id="@+id/mp1_seekBar1"
android:layout_width="276dp"
android:layout_height="20dp"
android:layout_below="@+id/mp1_rl1"
android:layout_centerHorizontal="true"
android:layout_marginTop="21dp"
android:maxHeight="24dip"
android:minHeight="20dip"
android:padding="0dp"
android:progressDrawable="@drawable/seekbar"
android:thumb="@drawable/seekbar_thumb"
android:thumbOffset="0dip" />
<TextView
android:id="@+id/mp1_tv_realtime"
android:layout_width="40dip"
android:layout_height="20dip"
android:layout_alignLeft="@+id/mp1_seekBar1"
android:layout_below="@+id/mp1_seekBar1"
android:gravity="center_horizontal"
android:text="00:00"
android:textColor="#000000"
android:textSize="12sp" />
<TextView
android:id="@+id/mp1_tv_duration"
android:layout_width="40dip"
android:layout_height="20dip"
android:layout_alignBaseline="@+id/mp1_tv_realtime"
android:layout_alignBottom="@+id/mp1_tv_realtime"
android:layout_alignRight="@+id/mp1_seekBar1"
android:text="00:00"
android:textColor="#000000"
android:textSize="12sp" />
<com.example.musicplay.LRC_textview_two
android:id="@+id/mp1_lrc"
android:layout_width="276dp"
android:layout_height="60dp"
android:layout_centerHorizontal="true"
android:layout_below="@+id/mp1_tv_realtime"
android:layout_marginTop="10dp" />
</RelativeLayout>
public class ClickListener implements OnClickListener{
Intent intent=new Intent(Musicplay_do.this,Music_service.class);
@Override
public void onClick(View v) {
switch(v.getId()){
case R.id.mp1_bt_menu:
Intent intent0 = new Intent(Musicplay_do.this,Musicmenu_do.class);
intent0.putExtra("position", position);
Musicplay_do.this.startActivity(intent0);
overridePendingTransition(R.anim.in_from_right, R.anim.out_to_left);
break;
case R.id.mp_bt_play:
if (isPause) {
bt_play.setBackgroundResource(R.drawable.bt_pause_press);
msg="play";
intent.putExtra("msg", msg);
startService(intent);
isPause = false;
}
else {
bt_play.setBackgroundResource(R.drawable.bt_play_press);
msg="pause";
intent.putExtra("msg", msg);
startService(intent);
isPause = true;
};break;
case R.id.mp_bt_next:
bt_play.setBackgroundResource(R.drawable.bt_pause_press);
msg="nextmusic";
intent.putExtra("msg", msg);
startService(intent);
isPause = false; break;
case R.id.mp_bt_up:
bt_play.setBackgroundResource(R.drawable.bt_pause_press);
msg="upmusic";
intent.putExtra("msg", msg);
startService(intent);
isPause = false; break;
case R.id.mp1_bt_circle:
if(circle==1){
bt_circle.setBackgroundResource(R.drawable.bt_circle2_press);
circle = 2;
msg = "";
intent.putExtra("circle", circle);
intent.putExtra("msg", msg);
startService(intent);
Toast.makeText(Musicplay_do.this, "顺序播放",
Toast.LENGTH_SHORT).show();
}else if(circle==2){
bt_circle.setBackgroundResource(R.drawable.bt_circle3_press);
circle = 3;
msg = "";
intent.putExtra("circle", circle);
intent.putExtra("msg", msg);
startService(intent);
Toast.makeText(Musicplay_do.this, "随机播放",
Toast.LENGTH_SHORT).show();
}else if(circle==3){
bt_circle.setBackgroundResource(R.drawable.bt_circle4_press);
circle = 4;
msg = "";
intent.putExtra("circle", circle);
intent.putExtra("msg", msg);
startService(intent);
Toast.makeText(Musicplay_do.this, "单曲循环",
Toast.LENGTH_SHORT).show();
}else if(circle==4){
bt_circle.setBackgroundResource(R.drawable.bt_circle1_press);
circle = 1;
msg = "";
intent.putExtra("circle", circle);
intent.putExtra("msg", msg);
startService(intent);
Toast.makeText(Musicplay_do.this, "列表循环",
Toast.LENGTH_SHORT).show();
};break;
}
}
4.5 歌词滚动显示
歌词滚动显示界面运行效果如图4-5所示。
图4-5歌词滚动显示页面运行效果
本界面为歌词滚动显示页面,歌词根据音乐播放进度不断更新歌词显示。
核心代码如下:
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if(canvas == null) {
return;
}
if(lrc!=null){
index =lrcIndex(currtime);
try {
setText("");
canvas.drawText(lrc.get(index).getLrc(), width / 2, height / 2, currentPaint);
float tempY = height / 2;
//画出本句之前的句子
for(int i = index - 1; i >= 0; i--) {
//向上推移
tempY = tempY - textHeight;
canvas.drawText(lrc.get(i).getLrc(), width / 2, tempY, notCurrentPaint);
}
tempY = height / 2;
//画出本句之后的句子
for(int i = index + 1; i < lrc.size(); i++) {
//往下推移
tempY = tempY + textHeight;
canvas.drawText(lrc.get(i).getLrc(), width / 2, tempY, notCurrentPaint);
}
} catch (Exception e) {
canvas.drawText("没有歌词可以显示", width / 2, height / 2, currentPaint);
}
}
else
canvas.drawText("没有歌词可以显示", width / 2, height / 2, currentPaint);
4.6 Appwidget
appwidget界面运行效果如图4-6所示。
图4-6appwidget运行效果
本界面为appwidget,上面有三个按钮用于控制音乐播放,同时可以显示当前播放音乐的歌名及歌手名。
核心代码如下:
public void onEnabled(Context context) {
// TODO 自动生成的方法存根
RemoteViews remote = new RemoteViews(context.getPackageName(),R.layout.appwidget2);
remote.setImageViewResource(R.id.app_bt_play, R.drawable.bt_play_press);
remote.setTextViewText(R.id.app_musicname, musicname);
remote.setTextViewText(R.id.app_singname, singer);
AppWidgetManager appwm = AppWidgetManager.getInstance(context);
ComponentName con = new ComponentName(context,Appwidget.class);
appwm.updateAppWidget(con, remote);
super.onEnabled(context);
}
@Override
public void onReceive(Context context, Intent intent) {
// TODO 自动生成的方法存根
super.onReceive(context, intent);
RemoteViews remote = new RemoteViews(context.getPackageName(),R.layout.appwidget2);
if(intent.getAction().equals("update_UI")){
isPause = intent.getBooleanExtra("isPause", true);
musicname = intent.getStringExtra("title");
singer = intent.getStringExtra("singer");
remote.setTextViewText(R.id.app_musicname, musicname);
remote.setTextViewText(R.id.app_singname, singer);
if(isPause){
remote.setImageViewResource(R.id.app_bt_play, R.drawable.bt_play_press);
}else{
remote.setImageViewResource(R.id.app_bt_play, R.drawable.bt_pause_press);
}}
AppWidgetManager appwm = AppWidgetManager.getInstance(context);
ComponentName con = new ComponentName(context,Appwidget.class);
appwm.updateAppWidget(con, remote);}
@Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager,
int[] appWidgetIds) {
// TODO 自动生成的方法存根
super.onUpdate(context, appWidgetManager, appWidgetIds);
Intent intent1 = new Intent();
Intent intent2 = new Intent();
Intent intent3 = new Intent();
//Intent intent4 = new Intent();
intent1.setAction(actionup);
intent2.setAction(actionplay);
intent3.setAction(actionnext);
//intent4.setAction("com.example.musicplay.Comein_do");
PendingIntent pintent1 = PendingIntent.getBroadcast(context, 0, intent1, 0);
PendingIntent pintent2 = PendingIntent.getBroadcast(context, 0, intent2, 0);
PendingIntent pintent3 = PendingIntent.getBroadcast(context, 0, intent3, 0);
//PendingIntent pintent4 = PendingIntent.getActivity(context, 0, intent4, 0);
RemoteViews remote = new RemoteViews(context.getPackageName(),R.layout.appwidget2);
remote.setTextViewText(R.id.app_musicname, musicname);
remote.setTextViewText(R.id.app_singname, singer);
remote.setImageViewResource(R.id.app_bt_play, R.drawable.bt_play_press);
remote.setOnClickPendingIntent(R.id.app_bt_up, pintent1);
remote.setOnClickPendingIntent(R.id.app_bt_play, pintent2);
remote.setOnClickPendingIntent(R.id.app_bt_next, pintent3);
//remote.setOnClickPendingIntent(R.id.app_ll, pintent4);
appWidgetManager.updateAppWidget(appWidgetIds, remote)}
4.7 通知栏界面
通知栏界面运行效果如图4-7所示。
图4-7通知栏运行效果
本界面为通知栏,通知栏实时显示歌曲名和歌手名。
核心代码如下:
notifmanager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
notif = new Notification(R.drawable.icn_notif,"MusicPlay",System.currentTimeMillis());
notif.flags |= Notification.FLAG_ONGOING_EVENT;
rv = new RemoteViews(this.getPackageName(),R.layout.notification);
notif.contentView = rv;
Intent intent = new Intent(this,Musicplay_do.class);
PendingIntent pendintent = PendingIntent.getActivity(this, 0, intent, 0);
notif.contentIntent = pendintent;
notifmanager.notify(1, notif);
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="60dp"
android:orientation="horizontal" >
<ImageView
android:id="@+id/notif_icn"
android:layout_width="40dp"
android:layout_height="40dp"
android:src="@drawable/icn_notif"
android:layout_marginLeft="10dp"
android:layout_marginTop="10dp"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="60dp"
android:orientation="vertical"
android:layout_marginLeft="20dp" >
<TextView
android:id="@+id/notif_musicname"
android:layout_width="wrap_content"
android:layout_height="30dp"
android:textColor="#ffffff"
android:text="未知"
android:gravity="center" />
<TextView
android:id="@+id/notif_singer"
android:layout_width="wrap_content"
android:layout_height="30dp"
android:textColor="#aaaaaa"
android:text="未知"
android:gravity="center" />
</LinearLayout>
</LinearLayout>
第5章 测试和总结
5.1 系统存在的问题及解决方案
当代码弄出来后,调试过程中出现了很多的问题。例如歌词的显示,这个时候只有不断的查询api,变量参数的问题,有时候仅仅是语法的错误。还有就是当时做的修改出现了问题,可是前面几个都没错。于是在这停留了好久,测试了一次又一次,最后在询问老师同学的时候才发现原来是调用错误。而其中我相信还有问题,相信和他们比起来,我们不算完美,还是有缺陷,比如界面、数据库中表的建立太过于复杂、编写程序前没有全面构思等等。我们还会进一步地增强。
5.2 收获与心得
经过又一次的实践专周,我们比以前又好多了。这一次我们的团队虽然是三个人,但我们一样不比别人差。先说编程上面,现在我们更加地熟练使用java语言,虽然现在学的也仅仅是皮毛,但相比之前,的确是好太多了,从第一学期的迷茫到现在的熟练掌握的确发生了太大的改变。这学期我们学习了很多,android各种组件的使用、activity。service等等。其中每一个的算法都不止一个。而我们学的也不止一个,我们知道了什么时候用什么样的算法,什么时候最简便。然后就是word文档和ppt,虽然这和课程无关,但是我们在生活上在以后的学习上都用的上。所以真的我们收获了很多。当然这些收获都离不开老师的习心教导,还有同学们的帮助。
参考文献
[1]java2实用教程(第四版)清华大学出版社.,2001.101~2012.804
[2]数据库系统概论(第四版)高等教育出版社2006.504~2013.522
致谢
我要首先感谢我们的任课老师胡恒和实践课程辅导我们的陈虹君老师,然后还有帮助我的同学们。谢谢!
电子科技大学成都学院
2016届实践专周成绩评定表