一個音樂播放需要資料
- 播放清單
- 是否在播放
- 播放模式
- 播放位置
- 目前歌曲播放進度
當清單改變時要通知界面清單改變,點選下一曲要通知界面進行下一曲資料顯示。當然可以使用通知來進行,不過改變一個資料就要通知,是不是很麻煩。再說,音樂播放界面有幾個,一個前台服務通知,一個主界面播放fragment,一個歌曲播放的fragment相當于有3個界面要更新,當然這些界面不一定是全在前台。這裡不使用通知,完成不同界面之間的資料傳遞以及fragment與service之間的資料傳遞(感覺就是使用靜态變量完成的)
觀察者模式大家應該比較熟悉,listview,adapter,java也實作了,在util包内有observer.其中有觀察者和被觀察者,最終完成效果如下
//被觀察者要實作的接口
/**
* @author xiaozhu
* @date 2015-8-13 下午8:15:35
*/
public interface Observable {
public void addObserver(Observer observer);// 添加觀察者
public void removeObserver(Observer observer);// 移除觀察者
public void notifyAllObserver(int command);// 通知所有觀察者
}
>
public class MusicData implements Observable {
private List<Observer> userList = new ArrayList<Observer>();// 記錄需要更新的界面
private static final MusicData musicData = new MusicData();// 單例模式
public static MusicData getInstance() {
return musicData;
}
// 播放模式
public static final int PLAYMODEL_SINGLELOOP = ;// 單曲循環
public static final int PLAYMODEL_LISTLOOP = ;// 清單循環
public static final int PLAYMODEL_SHUFFLEPLAY = ;// 随機播放
// 更新
public static final int COMMAND_UPDATE_PROGRESS = ;// 更新進度條
public static final int COMMAND_UPDATE_VIEW = ;// 更新界面
public static final int COMMAND_UPDATE_PLAY_PAUSE = ;//播放——暫停
public static final int COMMAND_UPDATE_PLAYMODE = ;//播放模式
public static final int COMMAND_UPDATE_SEEKTO = ;//播放模式
private List<Song> songList;// 播放清單
private boolean isPlaying;// 是否在播放
private int playMode;// 播放模式
private int position;// 播放位置
private int currentProgress;// 目前歌曲播放進度
public MusicData() {
this.songList = new ArrayList<Song>();
this.isPlaying = false;
this.playMode = PLAYMODEL_LISTLOOP;
this.position = -;
this.currentProgress = -;
}
public void init(List<Song> songList, int position) {// 更換目前播放清單
this.songList = songList;
this.position = position;
this.isPlaying = false;
this.playMode = PLAYMODEL_LISTLOOP;
this.currentProgress = -;
notifyAllObserver(COMMAND_UPDATE_VIEW);
}
@Override
public void addObserver(Observer observer) {
userList.add(observer);
}
@Override
public void removeObserver(Observer observer) {
userList.remove(observer);
}
@Override
public void notifyAllObserver(int command) {
for (Observer observer : userList) {
observer.update(this, command);
}
}
...
}
被觀察者使用單例模式,保證目前播放所需資料隻有一個
//觀察者要實作的接口
/**
* @author xiaozhu
* @date 2015-8-13 下午8:15:35
*/
public interface Observer {
public void update(Observable observable,int command);
}
為什麼要在update()裡面加個command,因為不是所有情況都一樣,或者每次都是界面全部更新。比如播放、暫停你需要通知界面更改播放圖示。
public class MusicPlayService extends Service implements Observer {
@Override
public void update(Observable observable, int command) {
switch (command) {
case MusicData.COMMAND_UPDATE_VIEW:
song = musicData.getSong();
if (mPlayer.isPlaying()) {
mPlayer.pause();
}
mPlayer.reset();
try {
if (!TextUtils.isEmpty(song.getLocallink())) {
mPlayer.setDataSource(song.getLocallink());
} else if (!TextUtils.isEmpty(song.getSonglink())) {
mPlayer.setDataSource(song.getSonglink());
} else {
return;
}
mPlayer.prepare();
if (musicData.isPlaying()) {
mPlayer.start();
}
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
} catch (IllegalStateException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
if(musicData.isPlaying()){
mPlayer.start();
}
break;
// case MusicData.COMMAND_UPDATE_PROGRESS:
// break;
case MusicData.COMMAND_UPDATE_SEEKTO:
mPlayer.seekTo(musicData.getCurrentProgress()*);// seekbar設定目前播放進度
break;
case MusicData.COMMAND_UPDATE_PLAY_PAUSE:
if(musicData.isPlaying()){
mPlayer.start();
}else{
mPlayer.pause();
}
break;
case MusicData.COMMAND_UPDATE_PLAYMODE:
break;
default:
break;
}
}
}
這裡隻貼出部分代碼
case MusicData.COMMAND_UPDATE_PROGRESS:
break;
case MusicData.COMMAND_UPDATE_SEEKTO:
break;
這裡對于進度條有一個PROGRESS和一個SEEKTO,
在我們音樂播放時進度條每秒都在更新,使用COMMAND_UPDATE_PROGRESS通知界面進行進度條更新,使用COMMAND_UPDATE_SEEKTO進行點選拖動進度條播放
再來看看playcontrol的update方法
@Override
public void update(Observable observable, int command) {
switch (command) {
case MusicData.COMMAND_UPDATE_VIEW:
updateView();
break;
case MusicData.COMMAND_UPDATE_PROGRESS:
tv_current.setText("" + musicData.getCurrentProgress());
sb_musicControl.setProgress(musicData.getCurrentProgress());// seekbar設定目前播放進度
break;
// case MusicData.COMMAND_UPDATE_SEEKTO:
// sb_musicControl.setProgress(musicData.getCurrentProgress());//
// seekbar設定目前播放進度
// break;
case MusicData.COMMAND_UPDATE_PLAY_PAUSE:
if (musicData.isPlaying()) {
ib_play.setImageResource(R.drawable.playcontrol_ib_pause_default);
} else {
ib_play.setImageResource(R.drawable.playcontrol_ib_play_default);
}
break;
case MusicData.COMMAND_UPDATE_PLAYMODE:
updateModeView();
}
}
很簡單,就是界面的更新
不想說明了,自己看代碼吧,下載下傳位址:
本音樂播放器http://download.csdn.net/detail/zjabc520/9016783
這個是沒有寫完的,裡面有些不合理位置,使用xutil,界面也很醜并且沒有優化,是以前寫的直接copy的,也沒有用注解,主要是想說明完成的想法:觀察者模式+單例。因為以前完成這個播放子產品,我用了綁定服務,也用過通知,但是效果都不好。
這裡面也實作了點選listview更改背景色和文字顔色,裡面的adapter這樣寫可以解決點選一項清單滑動時後面背景顔色也變的問題。
還有百度音樂的排行榜API,網上查的,不過這個API不是很理想。
好了,要是大家還有更好的實作這類問題(資料改變即通知界面更新)想法,歡迎分享。