音乐播放获取数据,配置权限,网络请求通知和刷新列表在这里不贴。只贴音乐播放服务和异步任务,有足够的注释。
一、音乐播放服务SongService
/**
* 播放歌曲的service
*/
public class SongService extends Service {
private MediaPlayer mediaPlayer;
private int position;
private boolean mediaIsReady;//播放器是否准备好
public SongService() {
}
@Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
// throw new UnsupportedOperationException("Not yet implemented");
return new SongBinder();
}
public class SongBinder extends Binder {
public SongService getService() {
return SongService.this;
}
}
/**
* 播放歌曲
* @param songFilePath
*/
public void playSong(String songFilePath){
//判断是不是重新播放
if (mediaPlayer==null) {
mediaPlayer = new MediaPlayer();
try {
mediaPlayer.setDataSource(songFilePath);
mediaPlayer.prepareAsync();
mediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
@Override
public void onPrepared(MediaPlayer mp) {
mediaIsReady=true;
mp.start();
}
});
} catch (IOException e) {
e.printStackTrace();
}
}else{
//否则是暂停后继续
mediaPlayer.seekTo(position);
mediaPlayer.start();
}
}
/**
* 暂停播放
*/
public void pauseSong(){
if (mediaPlayer!=null&&mediaPlayer.isPlaying()){
position=mediaPlayer.getCurrentPosition();//记录播放位置
mediaPlayer.pause();
}
}
/**
* 停止播放
*/
public void stopSong(){
if(mediaPlayer!=null||mediaPlayer.isPlaying()){
position=0;
mediaPlayer.stop();
mediaPlayer.release();
mediaPlayer=null;
}
}
@Override
public void onDestroy() {
super.onDestroy();
if(mediaPlayer!=null){
mediaPlayer.stop();
mediaPlayer.release();
mediaPlayer=null;
}
}
/**
* 获取媒体总长度
* @return
*/
public int getDuration(){
if (mediaPlayer!=null){
return mediaPlayer.getDuration();
}
return 0;
}
/**
* 获取当前播放位置
* @return
*/
public int getCurrentPosition(){
if (mediaPlayer!=null){
return mediaPlayer.getCurrentPosition();
}
return 0;
}
/**
* 位置跳转
* @param position
*/
public void seekTo(int position){
if (mediaPlayer!=null&&mediaPlayer.isPlaying()){
mediaPlayer.seekTo(position);
}
}
/**
* 判断播放器是否准备好了
* @return
*/
public boolean mediaPlayerIsReady(){
return mediaIsReady;
}
}
二、异步任务SongAsyncTask ,为方便维护,代码简洁清晰,没有写内部类,是一个独立的类
/**
* 播放音乐的异步任务
* Created by Devin Chen on 2016/12/18.
*/
public class SongAsyncTask extends AsyncTask<String,Integer,String> {
private Context context;//上下文对象
private SongService service;//音乐播放服务对象,服务里面有足够的播放控制方法和状态获取方法
private SeekBar seekBar;//搜索条对象,也可以传入显示进度变化需要更新的其他对象
/**
* 构造方法,传递必要的参数
* @param context
* @param service
* @param seekBar
*/
public SongAsyncTask(Context context, SongService service, SeekBar seekBar) {
this.context = context;
this.service = service;
this.seekBar = seekBar;
}
/**
* 异步任务开始时调用
*/
@Override
protected void onPreExecute() {
super.onPreExecute();
//Log.i("SongAsyncTask","SongAsyncTask start...");
}
/**
* 任务结束时调用
* @param s
*/
@Override
protected void onPostExecute(String s) {
super.onPostExecute(s);
Log.i("SongAsyncTask","SongAsyncTask over!");
}
/**
* publishProgress执行后调用,接收到进度值进行UI更新
* @param values
*/
@Override
protected void onProgressUpdate(Integer... values) {
super.onProgressUpdate(values);
seekBar.setMax(service.getDuration());//设置媒体总长度
seekBar.setProgress(values[0]);//设置当前进度
//Log.i("SongAsyncTask","总长度:"+service.getDuration());
//Log.i("SongAsyncTask","当前位置:"+values[0]);
}
/**
* 后台处理程序
* @param params
* @return
*/
@Override
protected String doInBackground(String... params) {
//用死循环监视
while (true){
//如果检测到媒体已经准备好,就开始发送进度
if(service.mediaPlayerIsReady()) {
publishProgress(service.getCurrentPosition());
}
}
}
}
三、最后说说怎么调用
音乐数据要在网络获取。我设计在service被绑定成功后向网络获取,也只有这时候,所需要的sevice才能获得,所以把异步任务的创建放在了ServiceConnection下的onServiceConnected方法内获取service和网络数据之后。
/**
* 服务连接对象
*/
class SongServiceConnection implements ServiceConnection {
@Override
public void onServiceConnected(ComponentName name, IBinder iBinder) {
songService = ((SongService.SongBinder) iBinder).getService();//获得service对象
SongHttpUtil.getSong(new SongGetDataMessage(), HTTP_METHOD_PLAY, songID);
//在获取到songService后创建异步任务
songAsyncTask = new SongAsyncTask(MusicPlayActivity.this, songService, seekPlay);
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
}
网络数据在工具类中获取,获取成功后发来通知,我用EventBus通知。收到通知后播放音乐,启动异步任务。
/**
* OnEventBus接收方法:音乐列表请求返回
*
* @param message
*/
@Subscribe
public void onEvent(SongGetDataMessage message) {
String action = message.getAction();
switch (action) {
case BaseMessage.REQUEST_ERROR:
Toast.makeText(MusicPlayActivity.this, SERVICE_ERROR, Toast.LENGTH_SHORT).show();
break;
case BaseMessage.REQUEST_SUCCESS:
SongJsonRootBean data = (SongJsonRootBean) message.getData();
if (data != null) {
Glide.with(this).load(data.getSonginfo().getPicBig()).into(imgSongImage);//加载音乐图片
songFilePath = data.getBitrate().getFileLink();//获取歌曲路径
songService.playSong(songFilePath);//播放歌曲
songAsyncTask.execute();//开始异步任务
} else {
Toast.makeText(MusicPlayActivity.this, SERVICE_GET_NO_DATA, Toast.LENGTH_SHORT).show();
}
}
}