Android第四次作业
一.团队
季澈 1600802044
张文君 1600802069
郭守杰 1600802041
二.apk下载链接
https://coding.net/u/mozhileixi/p/music/git/raw/master/app-debug.apk
三.代码链接
https://git.coding.net/mozhileixi/music.git
四.团队项目
运行效果视频:https://coding.net/u/mozhileixi/p/music/git/raw/master/Screen%20Record_2019-01-03-18-06-39.mp4
1.项目总体效果
进入界面(进入app前显示界面,借用网易云页面)
主界面(想实现网络搜索歌曲,但是实现,因此仅制作了UI界面,底部的功能均未实现)
歌曲列表
播放界面
2.项目效果描述及功能
点击app,先弹出进入界面,借鉴于网易云图片,首页为各功能显示,共有两个功能,网络搜索和本地搜索,由于下载歌曲连接的权限问题,暂未实现;本地搜索功能会搜集设备上所有MP3文件,点击本地音乐,会显示所有搜集到的歌曲,点击其中一首歌曲后跳转到播放界面,在播放界面有上一曲,下一曲,开始暂停,顺序播放,随机播放,单首播放,音量的控制,进度条,歌词,可以删除歌曲。
五.关键代码
获取歌词:对获取到的歌词进行解析。
public static List<LrcRow> createRows(String standardLrcLine){ try{ if (standardLrcLine.indexOf("[") == 0){ if (standardLrcLine.indexOf("]") == 6 ||standardLrcLine.indexOf("]") == 9 ){ }else{ if (standardLrcLine.indexOf(".") == 6){ }else { return null; } } }else{ return null ; } int lastIndexOfRightBracket = standardLrcLine.lastIndexOf("]"); String content = standardLrcLine.substring(lastIndexOfRightBracket + 1, standardLrcLine.length()); String times = standardLrcLine.substring(0,lastIndexOfRightBracket + 1).replace("[", "-").replace("]", "-"); String arrTimes[] = times.split("-"); List<LrcRow> listTimes = new ArrayList<LrcRow>(); for(String temp : arrTimes){ if(temp.trim().length() == 0){ continue; } LrcRow lrcRow = new LrcRow(temp, timeConvert(temp), content); listTimes.add(lrcRow); } return listTimes; }catch(Exception e){ Log.e(TAG,"createRows exception:" + e.getMessage()); return null; } }
获取本地歌曲:
public List<Song> getLocalMusci(Context context) { List<Song> list1 = new ArrayList<Song>(); int position = 0; Cursor cursor = context.getContentResolver() .query(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,null,null,null,MediaStore.Audio.AudioColumns.IS_MUSIC); for (cursor.moveToFirst();!cursor.isAfterLast(); cursor.moveToNext()) { Song song = new Song(); song.setSinger(cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.ARTIST))); song.setDuration(cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.DURATION))); song.setPath(cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.DATA))); song.setALLName(cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.DISPLAY_NAME))); song.setSong(cursor.getSring(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.DISPLAY_NAME))); song.setSize(cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.SIZE))); song.setId(cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media._ID))); if(song.getSong().contains("-")){ String Name[] = song.getSong().split("-"); String name = Name[1].toString().split(".mp3")[0].indexOf("[mqms2]") > 0 ? Name[1].toString().split(".mp3")[0].substring(0, Name[1].toString().split(".mp3")[0].indexOf("[mqms2]")) : Name[1].toString().split(".mp3")[0]; song.setSong(name); song.setSinger(Name[0]); } if (song.getDuration()/(1000 * 60) >= 1) { song.setPosition(position); list1.add(song); Log.i("songsong","+"+song.getALLName()+song.getPath()); position++; } Log.i("getMUSIC","TTTTTTTTTTT3"+list1.size()); } cursor.close(); if (list == null) { list = list1; } return list1; }
随机播放,单曲循环,顺序播放核心代码:
case R.id.iv_mode: if (mode == MusicUtil.TYPE_ORDER) { Toast.makeText(this, "已切换为随机模式", Toast.LENGTH_SHORT).show(); mode = MusicUtil.TYPE_RANDOM; ivMode.setImageResource(R.drawable.play_btn_shuffle_selector); MusicUtil.getInstance().setPatten(MusicUtil.TYPE_RANDOM); } else if (mode == MusicUtil.TYPE_RANDOM) { Log.i("pat2", "" + mode); Toast.makeText(this, "已切换为单曲循环", Toast.LENGTH_SHORT).show(); this.mode = TYPE_SINGLE; ivMode.setImageResource(R.drawable.play_btn_one_selector); MusicUtil.getInstance().setPatten(TYPE_SINGLE); Log.i("pat4", "" + mode); } else if (mode == TYPE_SINGLE) { Log.i("pat5", "" + mode); Toast.makeText(this, "已切换为顺序播放", Toast.LENGTH_SHORT).show(); this.mode = MusicUtil.TYPE_ORDER; ivMode.setImageResource(R.drawable.play_btn_loop_selector); MusicUtil.getInstance().setPatten(MusicUtil.TYPE_ORDER); Log.i("pat6", "" + mode); } break;
下一首,上一首,暂停,播放核心代码:
case R.id.iv_prev: if (!isplay) { isplay = true; ivPlay.setImageResource(R.drawable.play_btn_pause_selector); } MusicUtil.getInstance().pre(); changInfo(); Intent startIntent2 = new Intent(this, MusicService.class); startIntent2.putExtra("action", MusicService.PREVIOUSMUSIC); startService(startIntent2); musicService.changNotifi(1); break; case R.id.iv_play: if (isplay) { ivPlay.setImageResource(R.drawable.play_btn_play_selector); isplay = false; } else { isplay = true; ivPlay.setImageResource(R.drawable.play_btn_pause_selector); } Intent startIntent1 = new Intent(this, MusicService.class); startIntent1.putExtra("action", MusicService.PLAYORPAUSE); startService(startIntent1); break; case R.id.iv_next: MusicUtil.getInstance().next(); changInfo(); if (!isplay) { isplay = true; ivPlay.setImageResource(R.drawable.play_btn_pause_selector); } Intent startIntent3 = new Intent(this, MusicService.class); startIntent3.putExtra("action", MusicService.NEXTMUSIC); startService(startIntent3); break; }
删除歌曲核心代码:
public static boolean deleteSong (Song song) { File file = new File(song.getPath()); if (file.isFile() && file.exists()) { file.delete(); MusicUtil.getInstance().changeList(song); musicAdapter.setList(MusicUtil.getInstance().getList()); return true; } return false; }
五.5名最优apk评论
1.第一名:https://www.cnblogs.com/JusperLee/p/10192769.html(李凯、季轩石组)
(1)功能:计划的事实的添加;获取计划编写的时间;整体架构使用mvp架构;使用了第三方库来实现WiFi查看等功能。
(2)优点:功能较为完善,体系较为清楚,界面较为简洁,按钮较为明显。
(3)缺点:结构较为粗糙,颜色较为单一深暗。
(4)假想:如果由我组进行该项目的更改,我组成员将变更架构并将界面更加清新化,力求有别于官方APP。
2.第二名:https://www.cnblogs.com/Suejun/p/10192755.html(苏毅俊、南加拉才让、周泽加、李长栋组)
(1)功能:上课点名;学习资料;共享论坛;考试;习题等功能。
(2)优点:功能较为完善,体系较为清楚,界面较为简洁,颜色较为丰富。
(3)缺点:按钮较为奇特,布局较为简单。
(4)假想:如果由我组进行该项目的更改,我组成员将变更颜色搭配及界面按钮分布。
3.第二名:https://www.cnblogs.com/mxl123/p/10199113.html(马秀莲、马玉花组)
(1)功能:登录;注册;发布动态;查看好友列表;消息等功能。
(2)优点:功能可以说是很好了,按钮较为简洁,体系较为清晰。
(3)缺点:界面可以说是很简单了,布局不太合常理。
(4)假想:如果由我组进行该项目的更改,我组成员将变更按钮布局,从界面简洁性等着手改造,力求其商业化。
4.第四名:https://www.cnblogs.com/hlpbk/p/10190166.html(韩丽萍、祁海燕组)
(1)功能:添加日记;保存日记;修改日记;删除日记等功能。
(2)优点:界面较为清新,功能较为完善
(3)缺点:按钮太简洁了,字体有些奇怪
(4)假想:如果由我组进行该项目的更改,我组成员将变更字体及布局体系。
5.第五名:https://www.cnblogs.com/gao98/p/10201768.html(马玉娟、高志杰、高怡组)
(1)功能:显示,添加,修改,删除课程信息;跳转显示当前时间的课程;显示课程表的详细信息。
(2)优点:界面较为清新,体系较为清晰,架构较为简短
(3)缺点:布局有些奇特,功能较少
(4)假想:如果由我组进行该项目的更改,我组成员将变更架构,添加更多的复杂体系
六.所遇到的问题
郭守杰 1600802041
问题一:安卓6.0权限问题,在模拟器上可以运行apk,但是安装到手机上就闪退,查了一下是由于从安卓6.0开始要手动请求权限
解决方法:在AndroidManifest.xml中添加权限获取代码 然后在mainActivity里添加函数,最后在OnCreate中调用。
问题二:想实现网络歌曲播放,但是没有歌曲库,没有歌曲版权,无法获取网络歌曲。所以说改问题没有解决。
张文君 1600802069
问题一:在实现单曲循环的功能时,点击单曲循环按钮,无法进行相应的操作,导致它只会播放下一曲,并不会单曲循环,但是在顺序播放中是正常的。
解决方法:通过仔细调试,发现单曲循环功能的代码并不是随机播放,而是下一首,也就是说,单曲循环功能并没有进行实际的编程,通过查询,了解到单曲循环实在当前Activity中重新调用初始化播放的代码,也就是继续播放当前的歌曲,跟随机播放相类似,随机播放时通过随机生成的一个数来播放不同歌曲。
问题二:声音功能的实现,在最初时遇到了很多问题,也是通过网上查询和一次次的调试,才将声音功能实现
解决方法:用seekBar来调节大小,查了资料后发现,AudioManager可以调节各种类型的声音的音量,不过要添加<uses-permission Android:name="android.permission.MODIFY_AUDIO_SETTINGS" /> 权限,否则无法控制音量,功能无法实现。
季澈1600802044:
问题一:如何自定义一个view组件?(以自定义一个ImageView组件为例)
定义一个Java类,
继承要自定义的组件类型,
重写其中的一些方法,
对原组件扩展
public class ImageAsyncView extends ImageView
{
protected void onDraw(Canvas canvas){ }
}
问题二:如何更改listview的间隔条宽度,颜色?
android:divider="#f00" <!-- ?divider设定间隔条的颜色-->
android:dividerHeight="8px" <!-- ?dividerHeight设定间隔条的宽度-->
七.项目分工
姓名 | 分工 | 工作比例 | 分数(10) |
季澈 | UI,部分功能的实现 | 32% | 8 |
郭守杰 | UI,编程,代码上传 | 36% | 8 |
张文君 | UI,编程,写博客 | 32% | 8 |