版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u010356768/article/details/83310975
效果图
要更新进度条,需要PlayMusicService中发送广播,每秒发送广播,广播中携带播放进度信息
因此在PlayMusicService的onCreate方法中开启一个线程,写在onCreate中保证只起一条线程
private boolean isLoop = true;
/**
* 当service实例创建时执行
*/
@Override
public void onCreate() {
super.onCreate();
//给mediaPlayer加监听
mediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
//音乐已经准备好
@Override
public void onPrepared(MediaPlayer mediaPlayer) {
mediaPlayer.start();
//发送广播,通知activity音乐已经开始播放
Intent intent = new Intent (Globalconsts.ACTION_MUSIC_STARTED);
sendBroadcast(intent);
}
});
//启动工作线程,每隔1s发送一次更新进度的广播
new updateProgressThread().start();
}
/**
* 更新进度的线程
* 每秒发送广播,广播中携带播放进度信息
*/
class updateProgressThread extends Thread{
@Override
public void run() {
while (isLoop){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//发送自定义广播
if(mediaPlayer.isPlaying()){
int total = mediaPlayer.getDuration();
int currentPosition = mediaPlayer.getCurrentPosition();
Intent intent = new Intent(Globalconsts.ACTION_UPDATE_MUSIC_PROGRESS);
intent.putExtra("total",total);
intent.putExtra("current",currentPosition);
sendBroadcast(intent);
}
}
}
}
MainActivity中修改广播接收器的代码
/**
* 注册广播接收器
*/
private void registMusicReceiver() {
receiver = new MusicInfoBroadCastReceiver();
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(Globalconsts.ACTION_MUSIC_STARTED);
intentFilter.addAction(Globalconsts.ACTION_UPDATE_MUSIC_PROGRESS);
this.registerReceiver(receiver, intentFilter);
}
......
/**
* 接收音乐信息的广播接收器
*/
class MusicInfoBroadCastReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (action.equals(Globalconsts.ACTION_UPDATE_MUSIC_PROGRESS)) {
//获取广播中的total\current
int total = intent.getIntExtra("total", 0);
int current = intent.getIntExtra("current", 0);
//更新seekbar
seekBar.setMax(total);
seekBar.setProgress(current);
String totalStr = Globalconsts.FORMAT.format(new Date(total));
String currentStr = Globalconsts.FORMAT.format(new Date(current));
tv_play_music_total_time.setText(totalStr);
tv_play_music_current_time.setText(currentStr);
} else if (action.equals(Globalconsts.ACTION_MUSIC_STARTED)) {
......
}
}
}
同时,Globalconsts增加
public static final SimpleDateFormat FORMAT = new SimpleDateFormat("mm:ss");
//音乐开始播放 广播action
public static final String ACTION_MUSIC_STARTED = "ACTION_MUSIC_STARTED";
给进度条增加拖拽事件,MainActivity中修改
bindMusicService()中的binder对象为全局变量,同时
private void setListeners() {
//给seekbar加监听
seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
if (fromUser) {//由用户引起
//seekto
binder.seekTo(progress);
}
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
}
});
......
}
PlayMusicService中MusicBinder 里增加seekTo方法
public class MusicBinder extends Binder{
//定义供客户端调用的方法
/**
* 跳转到相应位置 继续播放/暂停
*/
public void seekTo(int position){
mediaPlayer.seekTo(position);
}
......
}
实现上一曲和下一曲
给三个图片(上一首,下一首,暂停图片)增加点击事件,同时在
MusicBinder中MusicBinder中增加
//暂停或开始播放
public void playOrPause(){
if(mediaPlayer.isPlaying()){
mediaPlayer.pause();
}else {
mediaPlayer.start();
}
}
MainActivity中onClick
case R.id.img_pre_music:
app.setPosition(app.getPosition() == 0 ? 0 : app.getPosition() - 1);
//这里会出空指针,当前歌曲只有在点击播放后才能拿到currentmusic的信息
final Music music = app.getCurrentMusic();
if (music.getBitrate() != null) {//基本信息已经加载过
//播放音乐
String url = music.getBitrate().getFile_link();
binder.playMusic(url);
} else {
//通过songid获取基本信息
musicModel.loadMusicInfoBySongId(music.getSong_id(), new MusicInfoCallback() {
@Override
public void onMusicInfoLoaded(Songinfo songinfo, BitrateModel bitrateModel) {
music.setBitrate(bitrateModel);
music.setSonginfo(songinfo);
String url = bitrateModel.getFile_link();
binder.playMusic(url);
}
});
}
break;
case R.id.img_pause_music:
binder.playOrPause();
break;
case R.id.img_next_music:
app.setPosition(app.getPosition() == app.getMusicList().size() - 1 ? 0 : app.getPosition() + 1);
final Music music2 = app.getCurrentMusic();
if (music2.getBitrate() != null) {//基本信息已经加载过
//播放音乐
String url = music2.getBitrate().getFile_link();
binder.playMusic(url);
} else {
//通过songid获取基本信息
musicModel.loadMusicInfoBySongId(music2.getSong_id(), new MusicInfoCallback() {
@Override
public void onMusicInfoLoaded(Songinfo songinfo, BitrateModel bitrateModel) {
music2.setBitrate(bitrateModel);
music2.setSonginfo(songinfo);
String url = bitrateModel.getFile_link();
binder.playMusic(url);
}
});
}
break;
解决点击上一曲下一曲按钮时,触发listview的onclick事件,给rlPlayMusic加上onTouch事件,返回true即可
private void setListeners() {
//给rlPlayMusic注册onTouch事件(触摸执行)
rlPlayMusic.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View view, MotionEvent motionEvent) {
//如果返回true
return true;
//如果返回false
//return false;
}
});
......
}
歌词显示
根据song_id获取歌曲信息的接口中lrclink字段是lrc歌词,根据链接下载lrc歌词
MusicModel中增加下载歌词的方法
public void downloadLrc(final String lrclink, final LrcCallback callback) {
AsyncTask<String,String,HashMap<String,String>> task = new AsyncTask<String, String, HashMap<String, String>>() {
@Override
protected HashMap<String, String> doInBackground(String... strings) {
try {
InputStream is = HttpUtils.getInputStream(lrclink);
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
String line = "";
HashMap<String,String> lrc = new HashMap<>();
while ((line = reader.readLine())!=null){//读到了歌词的一行
if(line.length()<10){//一行中的数据不够解析
continue;
}
//line:[00:07.00]音乐推广营销:奔跑怪物
//由于是显示每秒的歌词,所以截取00:07
String key = line.substring(1,6);
String value;
if(line.length() == 10){//说明只有时间
value = "";
}else {
value = line.substring(10);
}
lrc.put(key,value);
}
return lrc;
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
@Override
protected void onPostExecute(HashMap<String, String> hashMap) {
//返回上面的lrc
callback.onLrcLoaded(hashMap);
}
};
task.execute();
}
在Music这个model中增加
private HashMap<String,String> lrc;
public HashMap<String, String> getLrc() {
return lrc;
}
public void setLrc(HashMap<String, String> lrc) {
this.lrc = lrc;
}
MainActivity中
/**
* 接收音乐信息的广播接收器
*/
class MusicInfoBroadCastReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (action.equals(Globalconsts.ACTION_UPDATE_MUSIC_PROGRESS)) {
......
MusicApplication app = MusicApplication.getApp();
Music music = app.getCurrentMusic();
HashMap<String,String> lrc = music.getLrc();
if(lrc!=null){//根据当前时间,获取歌词内容,更新textview
String lrcContent = lrc.get(currentStr);
if(lrcContent!=null){
img_play_music_lrc.setText(lrcContent);
}
}
} else if (action.equals(Globalconsts.ACTION_MUSIC_STARTED)) {
......
//更新页面上其他
tv_play_music_title.setText(music.getSonginfo().getTitle());
tv_play_music_singer.setText(music.getSonginfo().getAuthor());
//下载歌词
musicModel.downloadLrc(music.getSonginfo().getLrclink(), new LrcCallback() {
@Override
public void onLrcLoaded(HashMap<String, String> lrc) {
//将下载好的歌词存入music对象
music.setLrc(lrc);
//把相对应的歌词呈现在界面上
//每隔1s更新歌词内容
//在更新音乐进度的广播接收器中更新即可
}
});
}
}
}