一、音樂播放器概述與分析
目前手機的音樂播放功能已經是大家比較關注的一個部分,不少在人在購買手機的時候都會關心手機的音樂播放的能力,這也足以看出目前大家對音樂播放功能的重視,所以一款性能良好的手機音樂播放器軟件一定會受到歡迎。和傳統(tǒng)的音樂播放器相比,手機播放音樂更加的容易攜帶,其他方面也都不輸于傳統(tǒng)音樂播放器,而且還具有網(wǎng)上聽音樂功能,所以開發(fā)一款受歡迎的手機音樂播放軟件是具有良好的市場和應用前景的。不同手機平臺的手機,所支持的音樂播放軟件也是各不相同,而現(xiàn)在最流行的手機平臺之一就是google 的android手機平臺,所以本課題就致力于開發(fā)出一款基于android手機平臺的音樂播放器,來滿足用戶的使用需求。
本次Android課設音樂播放器完成的基本功能有:
(1)主界面音樂播放管理:實現(xiàn)音樂的播放、暫停、播放進度條顯示及拉動、播放上一首、播放下一首、播放模式的列表循環(huán)、單曲循環(huán)、隨機播放等基本功能。
(2)通知欄音樂播放管理:使用Service、BroadcastReceiver可以在狀態(tài)通知欄實現(xiàn)音樂播放的基本功能、打開和退出等功能。
(3)桌面小組件音樂播放管理:使用Service、BroadcastReceiver、重寫AppWidgetProvider類在桌面以小組件的方式實現(xiàn)音樂播放基本功能。
(4)音樂搜索管理:獲取QQ音樂的音樂數(shù)據(jù),實現(xiàn)音樂搜索,保存并顯示搜索記錄,可對歷史搜索記錄進行刪除和清空。
(5)歌單管理:獲取QQ音樂的音樂數(shù)據(jù)的榜單信息,實現(xiàn)榜單歌單,可添加歌曲到我喜歡和播放列表等。
二、音樂播放器的設計
針對音樂播放器系統(tǒng)的功能進行詳細分析,整個應用程序應劃分為3個模塊,分別是程序啟動、用戶界面和數(shù)據(jù)庫適配器。
程序啟動時需要連接網(wǎng)絡訪問數(shù)據(jù),獲取數(shù)據(jù)并更新顯示到主界面榜單列表頁面中,具體如下圖所示:
用戶界面模塊包括榜單列表的主界面、用戶界面、播放界面、搜索界面、播放界面、歌單界面,具體如下圖所示:
數(shù)據(jù)庫模塊數(shù)據(jù)庫適配器主要對存入數(shù)據(jù)庫的專輯圖片、專輯名稱、歌手、歌名、音樂、付費情況數(shù)據(jù)進行管理,包括添加、刪除、查詢相關數(shù)據(jù),具體如下圖所示:
用戶進入音樂播放器后,會看到榜單列表的主界面。在主界面上進行的各種操作,截圖如下流程圖所示:
(1)在主界面(榜單列表)時,可以選擇點擊播放列表,查看播放列表中的歌曲,如有想要播放的音樂,點擊歌曲進入播放,否則可以選擇關閉按鈕關閉播放列表回到原來的界面,也可以通過歌曲欄中的播放按鈕播放當前歌曲。
(2)在主界面(榜單列表)中點擊歌曲欄,可以進入播放界面,進行播放音樂的操作,如播放、暫停、上一首、下一首,以及更改播放模式,或者返回主界面。
(3)在主界面(榜單列表)中點擊“我的”可以進入用戶界面,在用戶界面中可以點擊“喜歡”查看喜歡列表的歌曲,點擊“最近”查看最近播放列表的歌單,或者返回主界面。
(4)在主界面(榜單列表)中點擊榜單列表中的榜單(包括我喜歡列表),可以查看榜單中的歌曲,如有想要播放的歌曲可以點擊歌曲播放,或者返回主界面。
(5)在主界面(榜單列表)中點擊“搜索”,可以在編輯欄輸入想要搜索的歌手、歌名、專輯等,查詢后出現(xiàn)相關歌單列表,選擇可以播放歌曲。同時,會顯示搜索歷史,點擊可以繼續(xù)搜索以前的記錄,或刪除歷史記錄,或清空所有歷史,否則選擇返回主界面。
(6)在播放界面中,滑動可查看歌詞,拖動進度條可拖動播放,點擊暫停或播放、上一首、下一首控制播放,點擊“模式”可實現(xiàn)隨機播放、順序播放、單曲循環(huán),也可查看播放列表。點擊“操作”可以添加我喜歡聲音控制,或者選擇關閉。
三、音樂播放器的實現(xiàn)
1、功能實現(xiàn)
1.1 獲取QQ音樂數(shù)據(jù)
//QQ音樂接口
public static String getMusicApi(int topid) {
return "https://c.y.qq.com/v8/fcg-bin/fcg_v8_toplist_cp.fcg?g_tk=5381&uin=0&format=json&inCharset=utf-8&outCharset=utf-8?ice=0&platform=h5&needNewCode=1&tpl=3&page=detail&type=top&topid=" + topid;
}
//獲取專輯圖片
public static String getAlbumImg(String albummid) {
return "https://y.gtimg.cn/music/photo_new/T002R300x300M000" + albummid + ".jpg";
}
//獲取播放地址
public static final String musicUrl = "http://ws.stream.qqmusic.qq.com/";
public static String getMusicKey(String songmid) {
return "https://u.y.qq.com/cgi-bin/musicu.fcg?format=json&data=" +
"{\"req_0\":{" +
"\"module\":\"vkey.GetVkeyServer\"," +
"\"method\":\"CgiGetVkey\"," +
"\"param\":{" +
"\"guid\":\"1\"," +
"\"songmid\":[\"" + songmid + "\"]," +
"\"uin\":\"1\"" +
"}}}";
}
//獲取歌詞
public static final String qqmusicHeadName = "Referer";
public static final String qqmusicHeadValue = "https://y.qq.com/portal/player.html";
public static String getLyric(String songmid) {
return "https://c.y.qq.com/lyric/fcgi-bin/fcg_query_lyric_new.fcg?format=json&nobase64=1&songmid=" + songmid;
}
//搜索歌曲、歌手
public static String getSearch(String name) {
return "https://c.y.qq.com/soso/fcgi-bin/client_search_cp?p=1&n=20&format=json&w=" + name;
}
1.2 搜索功能
private void searchMusic() {
musicList.clear();
musicAdapter.notifyDataSetChanged();
mPresenter.getData(toolbar.getText());
dbHelper.insertData(toolbar.getText());
historyAdapter.setList(dbHelper.queryData());
layoutHistory.setVisibility(View.GONE);
rvMusic.setVisibility(View.VISIBLE);
}
1.3 桌面組件
@Override
public void onEnabled(Context context) {
super.onEnabled(context);
Log.d(TAG, "onEnabled: ");
//第一個被添加
}
@Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
super.onUpdate(context, appWidgetManager, appWidgetIds);
Log.d(TAG, "onUpdate: ");
RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.music_widget);
views.setImageViewResource(R.id.mw_albumimg, R.drawable.pic_launcher);
views.setTextViewText(R.id.mw_text, "選擇一首音樂");
views.setProgressBar(R.id.mw_progress, 100, 0, false);
views.setOnClickPendingIntent(R.id.mw_layout, startActivity(context));
views.setOnClickPendingIntent(R.id.mw_play, sendBrocast(context, ACTION_WIDGET_PLAY));
views.setOnClickPendingIntent(R.id.mw_previous, sendBrocast(context, ACTION_WIDGET_PREVIOUS));
views.setOnClickPendingIntent(R.id.mw_next, sendBrocast(context, ACTION_WIDGET_NEXT));
appWidgetManager.updateAppWidget(appWidgetIds, views);
}
@Override
public void onDisabled(Context context) {
super.onDisabled(context);
Log.d(TAG, "onDisabled: ");
//最后一個被移除
}
@Override
public void onReceive(Context context, Intent intent) {
super.onReceive(context, intent);
Log.d(TAG, "onReceive: " + intent.getAction());
if (MusicPlayerUtils.isMusicPlayer()) {
MyMusicPlayerView mPlayerView = (MyMusicPlayerView) XXPlayerManager.instance().getCurrentPlayer();
switch (intent.getAction()) {
case ACTION_WIDGET_UPDATE:
updatePlayer(context, mPlayerView);
break;
case ACTION_WIDGET_PLAY:
if (mPlayerView.isIdle()) {
mPlayerView.start();
} else if (mPlayerView.isPlaying() || mPlayerView.isBufferingPlaying()) {
mPlayerView.pause();
} else if (mPlayerView.isPaused() || mPlayerView.isBufferingPaused() ||
mPlayerView.isCompleted() || mPlayerView.isError()) {
mPlayerView.restart();
}
break;
case ACTION_WIDGET_PREVIOUS:
mPlayerView.playNext(false);
break;
case ACTION_WIDGET_NEXT:
mPlayerView.playNext(true);
break;
}
} else {
switch (intent.getAction()) {
case ACTION_WIDGET_PLAY:
case ACTION_WIDGET_PREVIOUS:
case ACTION_WIDGET_NEXT:
Toast.makeText(context, "選擇一首音樂", Toast.LENGTH_SHORT).show();
break;
}
}
}
1.4 通知欄
//更新通知欄
private void updateViews(RemoteViews views) {
Log.d(TAG, "updateViews: " + isPlaying);
if (isPlaying) {
notification.contentView = views;
notificationManager.notify(NOTIFICATION_ID, notification);
Intent intent = new Intent(this, MusicWidgetProvider.class);
intent.setAction(MusicWidgetProvider.ACTION_WIDGET_UPDATE);
sendBroadcast(intent);
}
}
//創(chuàng)建通知欄
private Notification createNotification() {
Notification.Builder builder;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {//8.0要通過NotificationChannel顯示通知
NotificationChannel channel = new NotificationChannel("id", "name", NotificationManager.IMPORTANCE_HIGH);
channel.enableLights(false);
channel.enableVibration(false);
channel.setVibrationPattern(new long[]{0});
channel.setSound(null, null);
notificationManager.createNotificationChannel(channel);
builder = new Notification.Builder(this, channel.getId());
} else {
builder = new Notification.Builder(this);
}
Notification notification = builder
.setSmallIcon(R.mipmap.ic_launcher)
.setContentTitle(getResources().getString(R.string.app_name))
.setContentIntent(startActivity())
.build();
return notification;
}
1.5 播放欄的暫停、播放、切歌、播放模式
public void onClick(View v) {
switch (v.getId()) {
case R.id.tv_music:
if (TextUtils.isEmpty(mPlayerView.getUrl())) {
((BaseActivity) getContext()).showToast("選擇一首音樂");
} else {
enterFullScreen();
}
break;
case R.id.iv_musiclist:
if (TextUtils.isEmpty(mPlayerView.getUrl())) {
((BaseActivity) getContext()).showToast("選擇一首音樂");
} else {
showListDialog();
}
break;
case R.id.ppv_music:
if (TextUtils.isEmpty(mPlayerView.getUrl())) {
((BaseActivity) getContext()).showToast("選擇一首音樂");
break;
}
if (mPlayerView.isIdle()) {
mPlayerView.start();
ppv_music.play();
} else if (mPlayerView.isPlaying() || mPlayerView.isBufferingPlaying()) {
mPlayerView.pause();
ppv_music.pause();
} else if (mPlayerView.isPaused() || mPlayerView.isBufferingPaused() ||
mPlayerView.isCompleted() || mPlayerView.isError()) {
mPlayerView.restart();
ppv_music.play();
}
break;
case R.id.ppv_play:
if (mPlayerView.isIdle()) {
mPlayerView.start();
ppv_play.play();
} else if (mPlayerView.isPlaying() || mPlayerView.isBufferingPlaying()) {
mPlayerView.pause();
ppv_play.pause();
} else if (mPlayerView.isPaused() || mPlayerView.isBufferingPaused() ||
mPlayerView.isCompleted() || mPlayerView.isError()) {
mPlayerView.restart();
ppv_play.play();
}
break;
case R.id.iv_mode:
if (mPlayerView.getPlayMode() == BasePlayerView.PLAY_MODE_LIST_LOOP) {//列表循環(huán)
iv_mode.setImageResource(R.drawable.ic_singleloop);
mPlayerView.setPlayMode(BasePlayerView.PLAY_MODE_LOOP);
ShareUtils.setMusicMode(getContext(), BasePlayerView.PLAY_MODE_LOOP);
((BaseActivity) getContext()).showToast("切換到單曲循環(huán)");
} else if (mPlayerView.getPlayMode() == BasePlayerView.PLAY_MODE_LOOP) {//單曲循環(huán)
iv_mode.setImageResource(R.drawable.ic_random);
mPlayerView.setPlayMode(BasePlayerView.PLAY_MODE_RANDOM);
ShareUtils.setMusicMode(getContext(), BasePlayerView.PLAY_MODE_RANDOM);
((BaseActivity) getContext()).showToast("切換到隨機播放");
} else if (mPlayerView.getPlayMode() == BasePlayerView.PLAY_MODE_RANDOM) {//隨機播放
iv_mode.setImageResource(R.drawable.ic_listloop);
mPlayerView.setPlayMode(BasePlayerView.PLAY_MODE_LIST_LOOP);
ShareUtils.setMusicMode(getContext(), BasePlayerView.PLAY_MODE_LIST_LOOP);
((BaseActivity) getContext()).showToast("切換到順序播放");
}
break;
case R.id.iv_list:
showListDialog();
break;
case R.id.iv_previous:
mPlayerView.playNext(false);
break;
case R.id.iv_next:
mPlayerView.playNext(true);
break;
}
}
2、界面實現(xiàn)
(1)榜單列表主界面由SimpleToolbar,SlidingTabLayout,ViewPager,MusicView四種組件組成,界面如下圖所示:
(2)用戶界面主要有RecyclerView,AppBarLayout,Toolbar,SimpleToolbar,CircleImageView,ImageView六種組件組成,界面如下圖所示:
(3)搜索界面主要有SearchToolbar,TextView,RecyclerView,F(xiàn)rameLayout,RecyclerView幾種組件,界面如下圖所示:
(4)播放界面主要控件ImageView,SimpleToolbar,ViewPager,TextView,SeekBar等組件組成,界面如下圖所示:
(5)播放列表的界面如下圖所示:
(6)音樂菜單的界面如下圖所示:
四、音樂播放器的演示
1、滑動或點擊榜單實現(xiàn)查看不同的榜單中的榜單列表,產生下圖變化。點擊其中的榜單,以點擊“我喜歡”為例,查看其中歌曲信息。
2、在主界面中點擊“我的”進入我的界面,,點擊“喜歡”后的列表,“最近播放”的列表分別如下圖所示。
3、在主頁面中點擊“搜索”進入搜索頁面,搜索“周深”出現(xiàn)相關的歌曲信息,輸入為空時,出現(xiàn)提示。刪除一項歷史記錄,清空歷史記錄分別如下圖所示。
4、在主頁或其他界面點擊播放欄的操作,點擊“播放”按鈕可以播放當前音樂,點擊“播放列表”會顯示播放列表信息。點擊整個播放欄,進入播放界面,點擊播放、暫停、下一首、上一首按鈕可實現(xiàn)播放控制。點擊播放模式分別彈出順序播放、循環(huán)播放、單曲循環(huán),以隨機播放為例。點擊播放列表還是如前面一樣,滑動屏幕可以實現(xiàn)歌詞界面,點擊操作欄,可將當前播放歌曲添加到“我喜歡”列表,同時支持搜索歌手和專輯信息、音量控制,分別如下圖所示。
5、桌面小組件和狀態(tài)通知欄的顯示分別如下圖所示。文章來源:http://www.zghlxwxcb.cn/news/detail-450255.html
需要源碼的小伙伴們可以在后臺私信我。文章來源地址http://www.zghlxwxcb.cn/news/detail-450255.html
到了這里,關于Android手機開發(fā)課程設計之音樂播放器的文章就介紹完了。如果您還想了解更多內容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網(wǎng)!