android-音樂播放器實現及原始碼下載(四)
本系列博文,詳細講述一個音樂播放器的實現,以及從網路解析資料獲取最新推薦歌曲以及歌曲下載的功能。
功能介紹如下:
1、獲取本地歌曲列表,實現歌曲播放功能。
2、利用硬體加速感應器,搖動手機實現切換歌曲的功能
3、利用jsoup解析網頁資料,從網路獲取歌曲列表,同時實現歌曲和歌詞下載到手機本地的功能。
4、通知欄提醒,實現仿QQ音樂播放器的通知欄功能.
涉及的技術有:
1、jsoup解析網路網頁,從而獲取需要的資料
2、android中訪問網路,獲取檔案到本地的網路請求技術,以及下載檔案到本地實現斷點下載
3、執行緒池
4、圖片快取
5、service一直在後臺執行
6、手機硬體加速器
7、notification通知欄設計
8、自定義廣播
9、android系統檔案管理
主要技術是這些,其中,利用jsoup解析網路網頁,從而獲取需要的資料,請參考我的博文:
本篇博文講述播放介面的設計和實現,以及做最後的總結。
這個是播放介面的截圖,仿QQ音樂播放介面的實現,程式碼如下:
/**
* 2015年8月15日 16:34:37
* 博文地址:http://blog.csdn.net/u010156024
*/
public class PlayActivity extends BaseActivity implements OnClickListener {
private LinearLayout mPlayContainer;
private ImageView mPlayBackImageView; // back button
private TextView mMusicTitle; // music title
private ViewPager mViewPager; // cd or lrc
private CDView mCdView; // cd
private SeekBar mPlaySeekBar; // seekbar
private ImageButton mStartPlayButton; // start or pause
private TextView mSingerTextView; // singer
private LrcView mLrcViewOnFirstPage; // single line lrc
private LrcView mLrcViewOnSecondPage; // 7 lines lrc
private PagerIndicator mPagerIndicator; // indicator
// cd view and lrc view
private ArrayList<View> mViewPagerContent = new ArrayList<View>(2);
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.play_activity_layout);
setupViews();
}
/**
* 初始化view
*/
private void setupViews() {
mPlayContainer = (LinearLayout) findViewById(R.id.ll_play_container);
mPlayBackImageView = (ImageView) findViewById(R.id.iv_play_back);
mMusicTitle = (TextView) findViewById(R.id.tv_music_title);
mViewPager = (ViewPager) findViewById(R.id.vp_play_container);
mPlaySeekBar = (SeekBar) findViewById(R.id.sb_play_progress);
mStartPlayButton = (ImageButton) findViewById(R.id.ib_play_start);
mPagerIndicator = (PagerIndicator) findViewById(R.id.pi_play_indicator);
// 動態設定seekbar的margin
MarginLayoutParams p = (MarginLayoutParams) mPlaySeekBar
.getLayoutParams();
p.leftMargin = (int) (App.sScreenWidth * 0.1);
p.rightMargin = (int) (App.sScreenWidth * 0.1);
mPlaySeekBar.setOnSeekBarChangeListener(mSeekBarChangeListener);
initViewPagerContent();
// 設定viewpager的切換動畫
mViewPager.setPageTransformer(true, new PlayPageTransformer());
mPagerIndicator.create(mViewPagerContent.size());
mViewPager.setOnPageChangeListener(mPageChangeListener);
mViewPager.setAdapter(mPagerAdapter);
mPlayBackImageView.setOnClickListener(this);
}
@Override
protected void onResume() {
super.onResume();
allowBindService();
}
@Override
protected void onPause() {
allowUnbindService();
super.onPause();
}
private OnPageChangeListener mPageChangeListener =
new OnPageChangeListener() {
@Override
public void onPageSelected(int position) {
if (position == 0) {
if (mPlayService.isPlaying())
mCdView.start();
} else {
mCdView.pause();
}
mPagerIndicator.current(position);
}
@Override
public void onPageScrolled(int arg0, float arg1, int arg2) {
}
@Override
public void onPageScrollStateChanged(int arg0) {
}
};
/**
* 拖動進度條
*/
private SeekBar.OnSeekBarChangeListener mSeekBarChangeListener =
new SeekBar.OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar seekBar, int progress,
boolean fromUser) {
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
int progress = seekBar.getProgress();
mPlayService.seek(progress);
mLrcViewOnFirstPage.onDrag(progress);
mLrcViewOnSecondPage.onDrag(progress);
}
};
private PagerAdapter mPagerAdapter = new PagerAdapter() {
@Override
public int getCount() {
return mViewPagerContent.size();
}
@Override
public boolean isViewFromObject(View view, Object obj) {
return view == obj;
}
/**
* 該方法是PagerAdapter的預載入方法,系統呼叫 當顯示第一個介面時,
* 第二個介面已經預載入,此時呼叫的就是該方法。
*/
@Override
public Object instantiateItem(ViewGroup container, int position) {
container.addView(mViewPagerContent.get(position));
return mViewPagerContent.get(position);
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
((ViewPager) container).removeView((View) object);
}
};
/**
* 初始化viewpager的內容
*/
private void initViewPagerContent() {
View cd = View.inflate(this, R.layout.play_pager_item_1, null);
mCdView = (CDView) cd.findViewById(R.id.play_cdview);
mSingerTextView = (TextView) cd.findViewById(R.id.play_singer);
mLrcViewOnFirstPage = (LrcView) cd.findViewById(R.id.play_first_lrc);
View lrcView = View.inflate(this, R.layout.play_pager_item_2, null);
mLrcViewOnSecondPage = (LrcView) lrcView
.findViewById(R.id.play_first_lrc_2);
mViewPagerContent.add(cd);
mViewPagerContent.add(lrcView);
}
@SuppressWarnings("deprecation")
private void setBackground(int position) {
Music currentMusic = MusicUtils.sMusicList.get(position);
Bitmap bgBitmap = MusicIconLoader.getInstance().load(
currentMusic.getImage());
if (bgBitmap == null) {
bgBitmap = BitmapFactory.decodeResource(getResources(),
R.drawable.ic_launcher);
}
mPlayContainer.setBackgroundDrawable(
new ShapeDrawable(new PlayBgShape(bgBitmap)));
}
/**
* 上一曲
*
* @param view
*/
public void pre(View view) {
mPlayService.pre(); // 上一曲
}
/**
* 播放 or 暫停
*
* @param view
*/
public void play(View view) {
if (mPlayService.isPlaying()) {
mPlayService.pause(); // 暫停
mCdView.pause();
mStartPlayButton
.setImageResource(R.drawable.player_btn_play_normal);
} else {
onPlay(mPlayService.resume()); // 播放
}
}
/**
* 上一曲
*
* @param view
*/
public void next(View view) {
mPlayService.next(); // 上一曲
}
/**
* 播放時呼叫 主要設定顯示當前播放音樂的資訊
*
* @param position
*/
private void onPlay(int position) {
Music music = MusicUtils.sMusicList.get(position);
mMusicTitle.setText(music.getTitle());
mSingerTextView.setText(music.getArtist());
mPlaySeekBar.setMax(music.getLength());
Bitmap bmp = MusicIconLoader.getInstance().load(music.getImage());
if (bmp == null)
bmp = BitmapFactory.decodeResource(getResources(),
R.drawable.ic_launcher);
mCdView.setImage(ImageTools.scaleBitmap(bmp,
(int) (App.sScreenWidth * 0.8)));
if (mPlayService.isPlaying()) {
mCdView.start();
mStartPlayButton
.setImageResource(R.drawable.player_btn_pause_normal);
} else {
mCdView.pause();
mStartPlayButton
.setImageResource(R.drawable.player_btn_play_normal);
}
}
private void setLrc(int position) {
Music music = MusicUtils.sMusicList.get(position);
String lrcPath = MusicUtils.getLrcDir() + music.getTitle() + ".lrc";
mLrcViewOnFirstPage.setLrcPath(lrcPath);
mLrcViewOnSecondPage.setLrcPath(lrcPath);
}
@Override
public void onPublish(int progress) {
mPlaySeekBar.setProgress(progress);
if (mLrcViewOnFirstPage.hasLrc())
mLrcViewOnFirstPage.changeCurrent(progress);
if (mLrcViewOnSecondPage.hasLrc())
mLrcViewOnSecondPage.changeCurrent(progress);
}
@Override
public void onChange(int position) {
setBackground(position);
onPlay(position);
setLrc(position);
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.iv_play_back:
finish();
break;
default:
break;
}
}
@Override
protected void onDestroy() {
super.onDestroy();
}
}
整個程式碼比較簡單,需要特別說明的是,播放介面並沒有和MediaPlayer類耦合,而是和PlayService耦合,對於歌曲的播放,暫停,下一曲、上一曲等操作都和PlayService進行互動,這樣做好處非常明顯,整個專案中所有對播放歌曲的操作都通過PlayService進行,同時,通過PlayService可以更新通知欄資訊。
**
總結
**
一、
專案中,用到了比較多的回撥介面,回撥介面確實非常好用,解決之間的耦合關係。
service類通過回撥介面OnMusicEventListener中的方法,呼叫activity類中的
public void onPublish(int percent);
public void onChange(int position);
兩個方法來實現UI的更新。
而Activity類中通過基類BaseActivity中的以下程式碼
private ServiceConnection mPlayServiceConnection = new ServiceConnection() {
@Override
public void onServiceDisconnected(ComponentName name) {
L.l(TAG, "play--->onServiceDisconnected");
mPlayService = null;
}
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
mPlayService = ((PlayService.PlayBinder) service).getService();
mPlayService.setOnMusicEventListener(mMusicEventListener);
onChange(mPlayService.getPlayingPosition());
}
};
private ServiceConnection mDownloadServiceConnection = new ServiceConnection() {
@Override
public void onServiceDisconnected(ComponentName name) {
L.l(TAG, "download--->onServiceDisconnected");
mDownloadService = null;
}
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
mDownloadService = ((DownloadService.DownloadBinder) service).getService();
}
};
/**
* 音樂播放服務回撥介面的實現類
*/
private PlayService.OnMusicEventListener mMusicEventListener =
new PlayService.OnMusicEventListener() {
@Override
public void onPublish(int progress) {
BaseActivity.this.onPublish(progress);
}
@Override
public void onChange(int position) {
BaseActivity.this.onChange(position);
}
};
完成與兩個service服務的繫結,實現與service服務的互動。
以上是兩個非常關鍵的方法實現兩者之間的互動,應該說是非常好的處理兩者之間的資訊傳遞。
其中在獲取網路歌曲列表的過程中,也是用到了回撥介面的方法進行資料傳遞,SongsRecommendation類中的
/**
* 回撥介面 獲取資料之後,通過該介面設定資料傳遞
*/
public interface OnRecommendationListener {
public void onRecommend(ArrayList<SearchResult> results);
}
這個介面就是進行結果傳遞的回撥介面。所以大家在看程式碼的過程中,務必瞭解並看懂回撥介面到底是如何進行的。
二、
專案中使用了比較多的執行緒池問題,大家務必瞭解執行緒池的用法。其實執行緒池用法非常簡單。
private ExecutorService mThreadPool;
mThreadPool = Executors.newSingleThreadExecutor();
mThreadPool.execute(new Runnable() {
@Override
public void run() {
ArrayList<SearchResult> result = getMusicList();
if (result == null) {
mHandler.sendEmptyMessage(Constants.FAILED);
return;
}
mHandler.obtainMessage(Constants.SUCCESS, result)
.sendToTarget();
}
});
以上便是執行緒池的基本用法了。easy!!
四、
本專案中的兩個service服務也是關鍵內容,關於service服務一直在後臺執行的內容,請參考我的博文:實現音樂播放器後臺Service服務一直存在的解決思路
以上四點是專案中比較重要的部分,博文寫的比較倉促,難免有什麼不好的地方,如果大家有什麼疑問或問題,歡迎給我留言,我一定儘快回覆大家!^_^【握手】
PS:
程式碼已更新,本地手機沒有MP3檔案的話,也不會出現崩潰。
相關推薦
android-音樂播放器實現及原始碼下載(四)
本系列博文,詳細講述一個音樂播放器的實現,以及從網路解析資料獲取最新推薦歌曲以及歌曲下載的功能。 功能介紹如下: 1、獲取本地歌曲列表,實現歌曲播放功能。 2、利用硬體加速感應器,搖動手機實現切換歌曲的功能 3、利用jsoup解析網頁資料,從網路
android-音樂播放器實現及原始碼下載(一)
從本文開始,詳細講述一個音樂播放器的實現,以及從網路解析資料獲取最新推薦歌曲以及歌曲下載的功能。 功能介紹如下: 1、獲取本地歌曲列表,實現歌曲播放功能。 2、利用硬體加速感應器,搖動手機實現切換歌曲的功能 3、利用jsoup解析網頁資料,從網路獲取歌曲
android-----音樂播放器的音量控制功能(開發)
一、佈局檔案 在RelativeLayout佈局裡設定一個ImageButton,點選其彈出一個SeekBar(用於音量調節), 再在其下面巢狀一個RelativeLayout,裡面包含兩個ImageView元件、一個SeekBar元件。 此外, anim---push_u
Android 音樂播放器實現歌詞顯示
LrcHandle.java: package com.example.welcome; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import
【Android】音樂播放器邊播邊快取(一)AndroidVideoCache的使用方法
最近在做音樂播放器類的需求,做了一段時間,抽出一段時間來整理一下。【前言】首先,記錄一下如何找到我們與需求相關的開源庫。可以在GitHub上進行搜尋,我的主要需求是邊播邊快取。因此我在GitHub上搜索“android”“cache”等關鍵詞,搜到了這個 AndroidVid
開源視訊播放器IjkPlayer使用記錄之(四)--多音軌的探路之旅
具體資訊可以見下:ffprobe -i test.mkv ffprobe version N-82166-g894e7ef Copyright (c) 2007-2016 the FFmpeg developers built with Apple LLVM version 8.0.0 (clang-80
Android音樂播放器的簡單實現
1、MusicService 音樂播放器的Service,裡面獲取音樂檔案,封裝了MediaPlayer,實現播放上一首和下一首,播放,停止,封裝成方法供Activity呼叫,獲取音樂的當前進度,總長度、名字,通過傳送廣播的方式發給Activity pa
Android 自定義音樂播放器實現
Android自定義音樂播放器一:首先介紹用了哪些Android的知識點:1 MediaPlayer工具來播放音樂2 Handle。因為存在定時任務(歌詞切換,動畫,歌詞進度條變換等)需要由Handle來處理Ui相關內容3 動態許可權申請(該應用程式讀取本地歌曲,並且設定音質
android 音樂播放器最簡單的實現
package com.example.mouse.laymen; import android.app.Activity; import android.media.MediaPlayer; import android.os.Bundle; import androi
Android 音樂播放器的實現(一)自定義按鈕的實現
Android 系統提供了MediaPlayer控制元件,讓我們能夠利用它實現音訊的播放。 而從學Android開始,在看教程的時候,我就想,我要自己做一個音樂播放器,因為一個完整的音樂播放器是有很多功能的,它涉及到很多方面的知識,可以幫助我們更好地學習和掌握關於Andro
android音樂播放器開發 SweetMusicPlayer 載入歌曲列表
路徑 本地 exc tao near import 設置 優先 特殊 上一篇寫了播放器的總體實現思路,http://blog.csdn.net/huweigoodboy/article/details/39855653,如今來總結下載入歌曲列表。 代碼地址
[嵌入式Linux專案實戰開發]基於QT4.7.4的音樂播放器實現與設計【2018年給力專案】
[嵌入式Linux專案實戰開發]基於QT4.7.4的音樂播放器實現與設計【2018年給力專案】是【創科之龍】團隊aiku嵌入式視訊教程系列製作的現有的音樂播放器。 主要功能實現: 1.新建工程,基類選擇Qwidget。雙擊開啟介面檔案,在介面檔案中建立label顯示時間、若干個tool
android 音樂播放器介面
一、團隊成員 姓名 學號 部落格地址 成凱 1600802002 http://www.cnblogs.com/ck03/ 黨康 1600802004 http://www.cnblogs.com/lxxxy/ 趙樂 1600802034 http://www.cnblogs.com/Z-y-H/ 二、
Android音樂播放器
主要功能介紹 實現音樂暫停,播放,下一首,上一首; 程式執行截圖 核心程式碼解析 功能鍵的實現 public void onClick(View v) { switch(v.getId()){
音樂播放器——實現後臺播放、搖搖切歌等功能
前言 首先宣告,小白一隻,android完全自學,若程式碼中有不妥或更簡便的方法求指教(大佬帶帶我)。。。 APP 歡迎介面 主介面 音樂介面 實現功能 1.遍歷本地音樂 2.音樂後臺播放 3.音樂封面之黑礁唱
go學習筆記(6)——音樂播放器實現
宣告:首先說明這個專案來自於許式偉的《Go語言程式設計》,書中也給出了詳盡的原始碼描述,不過程式碼中還是存在一些問題,首先說明一下所存在的問題問題一:音樂的播放結構體中定義了五個屬性欄位,在後面賦值的時候又變成了六個欄位的賦值問題二:Play函式在呼叫的時候多傳遞了兩個引數,
個人APP樂逗專案(內部音樂播放器實現,開源MaskProgressView使用)
1.所需工具 進度條: GitHub 獲取: 也可以免積分下載 音樂播放器進度條library : 2.效果演示 實現功能: (1) 音樂播放 (音樂播放地址URL) (2) 進度條 (MaskProgressVi
android 音樂播放器小案例
案例主目的是為了複習一下Service服務 Handler訊息機制 學習一下mediaplayer類 和了解自定義控制元件 MainAcitivity.java package com.alleged.musicPlay; import android
android音樂播放器播放音樂卡
自己在練習時寫了一個音樂播放器,但是放音樂的時候會卡 經過調查,才知道是在設定seekbar監聽的onProgressChanged這個方法中設定了player.seekTo(seekBar.getProgress());這樣就造成了音樂播放進度條改變,然後進度條的改變又會
Android音樂播放器中的歌詞同步學習分析
在網上查了一下資料,感謝 http://www.cr173.com/html/20184_1.html 給了我思路,可以說他提供了最基本的歌詞同步的功能,我在其上面添加了自己的修改的程式碼。 主要是自己為了實現歌詞同步,並且通過移動seekbar,改變歌曲的歌詞位置。當然還