一.團隊html
季澈 1600802044android
張文君 1600802069git
郭守傑 1600802041編程
二.apk下載連接canvas
https://coding.net/u/mozhileixi/p/music/git/raw/master/app-debug.apk網絡
三.代碼連接架構
https://git.coding.net/mozhileixi/music.gitapp
四.團隊項目ide
運行效果視頻: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 |