Android 音樂APP核心功能的實(shí)現(xiàn)(掃描本地犯眠、Service播放、循環(huán)模式症革、進(jìn)度更新筐咧、列表增刪等)

一、前言

? ? ? 自己做的音樂APP的界面部分已完成,各種功能基本實(shí)現(xiàn)了量蕊。但是我對音樂后臺播放這一塊(Service)不太滿意铺罢。因?yàn)橹皩ervice接觸得不多,所以沒有一個(gè)明確的規(guī)劃残炮,想要實(shí)現(xiàn)什么就往Service里添加新的需要實(shí)現(xiàn)的功能韭赘,導(dǎo)致原來的Service的代碼十分臃腫和凌亂。

? ? ? 一款音樂APP势就,最核心的業(yè)務(wù)就是播放音樂泉瞻,所以設(shè)計(jì)好一個(gè)完善的音樂APP的Service十分有必要。自己在動(dòng)手寫的時(shí)候參考了網(wǎng)上許多的例子苞冯,Github里完整的項(xiàng)目袖牙,由于編碼風(fēng)格和自己的不太一樣,理解起來效率很低舅锄,一些博客里發(fā)布的僅有單個(gè)功能的源碼又太簡單鞭达。因此我整理了下自己的思路,做一次總結(jié)皇忿,以獲得更好的提升畴蹭。

二、實(shí)現(xiàn)功能

? ? ? 這個(gè)MusicService主要實(shí)現(xiàn)了如下功能:

基本功能

? ? ? 播放本地歌曲禁添、網(wǎng)絡(luò)歌曲撮胧,實(shí)現(xiàn)播放、暫停老翘、下一首芹啥、選擇循環(huán)模式、拖動(dòng)進(jìn)度條改變播放位置等基本功能铺峭。

讀取SQLIte數(shù)據(jù)

? ? ? 1墓怀、啟動(dòng)應(yīng)用后,能夠獲取前一次未播放完的音樂信息(如當(dāng)前時(shí)間卫键、歌曲總長傀履、進(jìn)度條位置、歌曲莉炉、歌手钓账、循環(huán)模式等),并裝入下端播放欄中絮宁,點(diǎn)“播放”在暫停處續(xù)播梆暮;

? ? ? 2、進(jìn)入本地音樂界面時(shí)绍昂,如之前已經(jīng)啟動(dòng)過引用并掃描過本地音樂啦粹,則直接載入歌曲信息偿荷,如還沒有掃描可點(diǎn)擊界面的右上角彈出Dialog選擇“掃描本地音樂”選項(xiàng)進(jìn)行掃描;

? ? ? 3唠椭、在MusicService通過SQLite獲得歌曲信息跳纳。

用戶體驗(yàn)

? ? ? 1、點(diǎn)擊播放欄“列表”圖標(biāo)贪嫂,通過DrawerLayout的方式彈出播放列表寺庄;

? ? ? 2、點(diǎn)擊本地音樂列表或者網(wǎng)絡(luò)歌單的歌曲即可播放撩荣,并且將當(dāng)前播放的音樂自動(dòng)添加至播放列表铣揉,當(dāng)用戶改變循環(huán)模式,或者增刪本地列表餐曹、播放列表的歌曲時(shí),MusicService均可正確地播放下一首歌曲敌厘;

? ? ? 3台猴、通過廣播發(fā)送通知,讓Activity更新UI俱两。

三饱狂、效果圖

? ? ? 效果圖如下所示:

4、關(guān)鍵思路

本Demo的Java文件包括:

? ? ? 后臺Service:

? ? ? MusicService挣棕,用于在后臺播放音樂以及進(jìn)行各種操作的服務(wù)類

? ? ? 前臺Activity

? ? ? Activity:MainActivity:用于進(jìn)入本地音樂界面和網(wǎng)絡(luò)音樂界面的活動(dòng)類

? ? ? LocalMusicActivity:顯示本地音樂列表界面的活動(dòng)類

? ? ? OnlineMusicActivity:實(shí)現(xiàn)網(wǎng)絡(luò)歌曲(也就是我APP中歌單)界面的活動(dòng)類

? ? ? 還有一些工具類少辣、線程類分別用于掃描本地音樂脆霎,適配ListView等延時(shí)操作,詳見源碼俊柔。

? ? ? 此外,還需要用到SQLite去對數(shù)據(jù)進(jìn)行存儲和提取活合,我建立了一個(gè)名為music.db的數(shù)據(jù)庫雏婶,并在這個(gè)數(shù)據(jù)庫里建立了playerbarinfotb、localmusictb白指、onlinemusictb留晚、playlisttb、loadlocalmusiclistviewtb這幾個(gè)表格告嘲,分別管理播放欄數(shù)據(jù)错维、本地音樂、網(wǎng)絡(luò)音樂橄唬、播放列表音樂赋焕、是否曾掃描并載入本地音樂等信息。

? ? ? 還需要在Activity里定義localsong_list轧坎、onlinesong_list和play_list分別存儲本地音樂宏邮、網(wǎng)絡(luò)歌曲以及播放列表的歌曲信息。

代碼運(yùn)行流程就是:

·初始化

? ? ??啟動(dòng)Activity時(shí)先對數(shù)據(jù)庫里的playerbarinfotb這一個(gè)表格中去搜索,如果存在數(shù)據(jù)蜜氨,就將播放欄各項(xiàng)信息提取出來械筛,初始化播放欄。

·進(jìn)入本地

? ? ? 進(jìn)入本地音樂后飒炎,搜索loadlocalmusiclistviewtb埋哟,如果存在數(shù)據(jù),說明已經(jīng)掃描過本地音樂郎汪,因此從localmusictb里將全部的歌曲信息提取出來赤赊,載入本地音樂界面的ListView中,如果loadlocalmusiclistviewtb不存在數(shù)據(jù)煞赢,就顯示“掃描本地”按鈕抛计,對手機(jī)上的本地音樂進(jìn)行掃描,并在掃描完成后將掃描結(jié)果載入ListView照筑。

? ? ? 在MusicService里吹截,用public static final String的語句定義好各種動(dòng)作,如:

? ? ? public?static?final?String?ACTION_UPDATE_TIME="ACTION_UPDATE_TIME";

? ? ? public?static?final?String?ACTION_PLAY_CURR_MUSIC="ACTION_PLAY_CURR_MUSIC";

? ? ? public?static?final?String?ACTION_PLAY_ONLINE_MUSIC="ACTION_PLAY_ONLINE_MUSIC";

? ? ? public?static?final?String?ACTION_PLAY_LOCAL_MUSIC="ACTION_PLAY_LOCAL_MUSIC";

? ? ? public?static?final?String?ACTION_PLAY_PLAYLIST_MUSIC="ACTION_PLAY_PLAYLIST_MUSIC";

? ? ? public?static?final?String?ACTION_DELETE_LOCALMUSIC="ACTION_DELET_LOCALMUSIC";

? ? ? public?static?final?String?ACTION_DELETE_PLAYLIST_MUSIC="ACTION_DELETE_PLAYLIST_MUSIC";

? ? ? public?static?final?String?ACTION_PLAY_NEXT="ACTION_PLAY_NEXT";

? ? ? public?static?final?String?ACTION_PLAY_ALL_LOCALMUSIC="ACTION_PLAY_ALL_LOCALMUSIC";

? ? ? public?static?final?String?ACTION_PLAY_ALL_ONLINEMUSIC="ACTION_PLAY_ALL_ONLINEMUSIC";

? ? ? public?static?final?String?ACTION_CLEAR_ALL_PLAYLIST="ACTION_CLEAR_ALL_PLAYLIST";

? ? ? public?static?final?String?ACTION_CHANGE_CIRCULATE_MODE="ACTION_CHANGE_CIRCULATE_MODE";

? ? ? 這些動(dòng)作顧名思義凝危,分別是“更新時(shí)間”波俄、“播放當(dāng)前播放欄音樂”、“播放網(wǎng)絡(luò)音樂”蛾默、“播放本地音樂”懦铺、“播放音樂列表里的音樂”、“刪除本地歌曲”支鸡、“刪除播放列表里的歌曲”冬念、“播放下一首”、“播放所有本地音樂”苍匆、“播放所有網(wǎng)絡(luò)音樂”刘急、“清空播放列表”等動(dòng)作。

·播放歌曲

? ? ? 如果點(diǎn)擊了本地音樂列表里的某一首歌浸踩,就通過

? ? ? intent.setAction(MusicService.ACTION_PLAY_LOCAL_MUSIC);

? ? ? 的方法叔汁,向intent添加了代表了“播放本地音樂”的這個(gè)動(dòng)作標(biāo)示,與此同時(shí)還通過

? ? ? Intetn.putExtra(“position”,position);

? ? ? 的方法傳入當(dāng)前點(diǎn)擊的歌曲在本地歌曲列表中的位置检碗,接著用

? ? ? startService(intent);

? ? ? 的方法啟動(dòng)項(xiàng)目的服務(wù)類MusicService据块。MusicService在onStartCommand()方法里通過

? ? ? if(intent.setAction.equals(MusicService.ACTION_PLAY_LOCAL_MUSIC);

? ? ? 的語句去判斷傳入的動(dòng)作標(biāo)識是什么,并執(zhí)行相應(yīng)的操作折剃。例如播放列表里有歌曲A另假、B、C怕犁、D边篮、E順序排列己莺,他們的播放路徑分別是“sdcard/a.mp3”、“sdcard/b.mp3”戈轿、“sdcard/c.mp3”凌受、“sdcard/d.mp3”、“sdcard/e.mp3”思杯,用戶點(diǎn)擊的是本地音樂列表里的第二首歌胜蛉,MusicService就開始獲取傳入的值position,為1(從0開始算起)色乾,在MusicService里提取本地音樂的數(shù)據(jù)庫誊册,通過position找到用戶點(diǎn)擊的是歌曲B。然后播放這首歌暖璧。

·添加

? ? ? 歌曲播放的同時(shí)案怯,程序會對播放列表的數(shù)據(jù)庫playlisttb進(jìn)行搜索,如果playlisttb里面沒有當(dāng)前播放的歌曲澎办,那么用insert語句將其添加至playlisttb殴泰,用.add()語句添加至play_list,并通過Adapter的.updateData()方法刷新播放列表的ListView界面浮驳。

? ? ? 歌曲播放時(shí)通過定時(shí)線程,每秒發(fā)送一次播放器信息廣播捞魁,當(dāng)前Activity接收到廣播后更新播放欄的信息至会。

·下一首

? ? ? 歌曲開始播放之后,在MusicService里執(zhí)行g(shù)etNextSong()的方法谱俭,根據(jù)循環(huán)模式奉件,獲取下一首播放的歌曲。列表循環(huán)的時(shí)候昆著,獲取歌曲B的下一首也即歌曲C县貌,單曲循環(huán)的時(shí)候,獲取夏一首歌曲也即歌曲B凑懂,隨機(jī)播放的時(shí)候煤痕,通過Ramdom取出一個(gè)范圍為0到(play_list.size()-1)的隨機(jī)數(shù)m,用play_list.get(m)的方法獲取下一首待播歌曲接谨。當(dāng)監(jiān)聽到當(dāng)前歌曲播放完畢后摆碉,執(zhí)行播放下一首。

·刪除

? ? ? 當(dāng)刪除本地音樂或者播放列表里的歌曲C時(shí)脓豪,也獲取音樂的position巷帝,為2,并發(fā)送刪除歌曲的動(dòng)作標(biāo)示到MusicService扫夜,MusicService根據(jù)position判斷刪除的是歌曲C楞泼,如果當(dāng)前循環(huán)模式是列表循環(huán)驰徊,刪中的正好是下一首待播的歌曲,那么就通過歌曲的路徑堕阔,獲取另外的正確的下一首待播歌曲棍厂,得到歌曲D(接著D又從播放列表中被刪除,getNextSong()又獲取歌曲E)

·循環(huán)

? ? ? 在MusicService里定義一個(gè)公共的int變量MUSIC_CIRCULATION_MODE印蔬,設(shè)置終態(tài)變量來表示循環(huán)模式勋桶,如public? static final int LIST_CIRCULATION=0表示列表循環(huán),public? static final int SINGLE_CIRCULATION=1表示單曲循環(huán)侥猬,public? static final int SHAFFULE=2表示隨機(jī)播放例驹。點(diǎn)擊播放欄的循環(huán)圖標(biāo)可以改變MusicService的公共變量MUSIC_CIRCULATION_MODE,點(diǎn)擊一次就輪次賦值列表循環(huán)退唠、單曲循環(huán)鹃锈、隨機(jī)播放這三個(gè)常量,并通過動(dòng)作標(biāo)示啟動(dòng)MusicService瞧预,MusicService根據(jù)switch(MUSIC_CIRCULATION_MODE)屎债,啟動(dòng)getNextSong()方法去獲取下一首待播歌曲。

·網(wǎng)絡(luò)歌單

? ? ? 網(wǎng)絡(luò)歌單的頁面在我自己的APP里是通過一個(gè)HttpThread的線程類去獲取我服務(wù)端上的歌單列表的垢油,在這個(gè)源碼里我就直接定義一個(gè)list并直接往里面添加歌曲信息了盆驹。只是歌曲的URL是我家局域網(wǎng)里服務(wù)端的歌曲地址,如有需要可以直接改成別的網(wǎng)絡(luò)歌曲連接滩愁。

·MainActivity

? ? ? 在這個(gè)源碼中我并沒有設(shè)置從本地音樂界面或網(wǎng)絡(luò)歌單界面跳轉(zhuǎn)回主界面的方法躯喇,返回主界面上通過菜單上的返回鍵進(jìn)行的,因此硝枉,為解決本地音樂界面或者網(wǎng)絡(luò)歌單界面返回主界面后廉丽,主界面由于沒有重新onCreate()而沒有更新播放列表的問題,我重寫了onResume()方法妻味,加入了一個(gè)刷新播放列表的ListView的方法正压。使得幾個(gè)界面的播放列表能保持同步。


5责球、源碼

? ? ??安卓音樂APP后臺Service源碼

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末焦履,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子棕诵,更是在濱河造成了極大的恐慌裁良,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,651評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件校套,死亡現(xiàn)場離奇詭異价脾,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)笛匙,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,468評論 3 392
  • 文/潘曉璐 我一進(jìn)店門侨把,熙熙樓的掌柜王于貴愁眉苦臉地迎上來犀变,“玉大人,你說我怎么就攤上這事秋柄』裰Γ” “怎么了?”我有些...
    開封第一講書人閱讀 162,931評論 0 353
  • 文/不壞的土叔 我叫張陵骇笔,是天一觀的道長省店。 經(jīng)常有香客問我,道長笨触,這世上最難降的妖魔是什么懦傍? 我笑而不...
    開封第一講書人閱讀 58,218評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮芦劣,結(jié)果婚禮上粗俱,老公的妹妹穿的比我還像新娘。我一直安慰自己虚吟,他們只是感情好寸认,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,234評論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著串慰,像睡著了一般偏塞。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上邦鲫,一...
    開封第一講書人閱讀 51,198評論 1 299
  • 那天烛愧,我揣著相機(jī)與錄音,去河邊找鬼掂碱。 笑死,一個(gè)胖子當(dāng)著我的面吹牛慎冤,可吹牛的內(nèi)容都是我干的疼燥。 我是一名探鬼主播,決...
    沈念sama閱讀 40,084評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼蚁堤,長吁一口氣:“原來是場噩夢啊……” “哼醉者!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起披诗,我...
    開封第一講書人閱讀 38,926評論 0 274
  • 序言:老撾萬榮一對情侶失蹤撬即,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后呈队,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體剥槐,經(jīng)...
    沈念sama閱讀 45,341評論 1 311
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,563評論 2 333
  • 正文 我和宋清朗相戀三年宪摧,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了粒竖。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片颅崩。...
    茶點(diǎn)故事閱讀 39,731評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖蕊苗,靈堂內(nèi)的尸體忽然破棺而出沿后,到底是詐尸還是另有隱情,我是刑警寧澤朽砰,帶...
    沈念sama閱讀 35,430評論 5 343
  • 正文 年R本政府宣布尖滚,位于F島的核電站,受9級特大地震影響瞧柔,放射性物質(zhì)發(fā)生泄漏漆弄。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,036評論 3 326
  • 文/蒙蒙 一非剃、第九天 我趴在偏房一處隱蔽的房頂上張望置逻。 院中可真熱鬧,春花似錦备绽、人聲如沸券坞。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,676評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽恨锚。三九已至,卻和暖如春倍靡,著一層夾襖步出監(jiān)牢的瞬間猴伶,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,829評論 1 269
  • 我被黑心中介騙來泰國打工塌西, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留他挎,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,743評論 2 368
  • 正文 我出身青樓捡需,卻偏偏與公主長得像办桨,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子站辉,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,629評論 2 354

推薦閱讀更多精彩內(nèi)容