1. 程式人生 > >Android開發 本地與線上音樂播放器(基於Service實現)

Android開發 本地與線上音樂播放器(基於Service實現)

專案裡需要做一個類似於QQ音樂,網易雲音樂一樣的實現本地與線上播放的音樂播發器。

本地的好做,查詢安卓自己的媒體庫ContentProvidre返回Cursor,一個個讀出來就好了。

關鍵是線上播放。

一開始在網上搜了搜Demo.找到一個線上播放的Demo.但看了看原始碼,線上播放那一部分是在Activity裡new 一個Thread,在Thread裡實現播放。

這樣做盡管能實現線上播放,但是和Activity的通訊變成了麻煩。畢竟還需要和Seekbar互動,實現拖拽進度,暫停,繼續等這樣的操作。

於是,自己在Service裡寫了一個線上播放。效果還不錯。‘

先看下最後的結果圖:

1.本地播放:

歌曲列表

播放介面,模仿網易雲音樂,背景根據專輯圖片高斯模糊

線上歌曲列表


2.線上播放,SeekBar裡的紅色代表當前進度,灰色代表線上緩衝進度,透明代表沒有緩衝到的。

接下來一步步說方法。

首先是本地播放:

根據ContentProvider查詢出一個包含所有本地音樂的Cursor.

1.用來獲取所有本地歌曲的MediaUtil.

MediaUtil.java

package com.lzw.util;

import java.io.FileDescriptor;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;

import android.content.ContentResolver;
import android.content.ContentUris;
import android.content.Context;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.BitmapFactory.Options;
import android.net.Uri;
import android.os.ParcelFileDescriptor;
import android.provider.MediaStore;
import android.util.Log;

import com.lzw.bean.SongBean;
import com.lzw.lmusicplayer.R;

public class MediaUtil {
	
	private static final Uri albumArtUri = Uri.parse("content://media/external/audio/albumart");

	public static ArrayList<SongBean> getAllSongs(Context context) {
		Cursor cursor = context.getContentResolver().query(
				MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, null, null, null,
				MediaStore.Audio.Media.DEFAULT_SORT_ORDER);
		
		ArrayList<SongBean> mp3Infos = new ArrayList<SongBean>();
		for (int i = 0; i < cursor.getCount(); i++) {
			cursor.moveToNext();
			SongBean mp3Info = new SongBean();
			long id = cursor.getLong(cursor
					.getColumnIndex(MediaStore.Audio.Media._ID));	
			String title = cursor.getString((cursor	
					.getColumnIndex(MediaStore.Audio.Media.TITLE))); 
			String artist = cursor.getString(cursor
					.getColumnIndex(MediaStore.Audio.Media.ARTIST)); 
			String album = cursor.getString(cursor
					.getColumnIndex(MediaStore.Audio.Media.ALBUM));	
			String displayName = cursor.getString(cursor
					.getColumnIndex(MediaStore.Audio.Media.DISPLAY_NAME));
			long albumId = cursor.getInt(cursor.getColumnIndex(MediaStore.Audio.Media.ALBUM_ID));
			long duration = cursor.getLong(cursor
					.getColumnIndex(MediaStore.Audio.Media.DURATION)); 
			long size = cursor.getLong(cursor
					.getColumnIndex(MediaStore.Audio.Media.SIZE)); 
			String url = cursor.getString(cursor
					.getColumnIndex(MediaStore.Audio.Media.DATA)); 
			int isMusic = cursor.getInt(cursor
					.getColumnIndex(MediaStore.Audio.Media.IS_MUSIC)); 
			if (isMusic != 0) { 
				mp3Info.setId(id);
				mp3Info.setTitle(title);
				mp3Info.setArtist(artist);
				mp3Info.setAlbum(album);
				mp3Info.setDisplayName(displayName);
				mp3Info.setAlbumId(albumId);
				mp3Info.setDuration(duration);
				mp3Info.setSize(size);
				mp3Info.setUrl(url);
				mp3Infos.add(mp3Info);
			}
		}
		return mp3Infos;
	}
	

	public static List<HashMap<String, String>> getMusicMaps(
			List<SongBean> mp3Infos) {
		List<HashMap<String, String>> mp3list = new ArrayList<HashMap<String, String>>();
		for (Iterator iterator = mp3Infos.iterator(); iterator.hasNext();) {
			SongBean mp3Info = (SongBean) iterator.next();                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          
			HashMap<String, String> map = new HashMap<String, String>();
			map.put("title", mp3Info.getTitle());
			map.put("Artist", mp3Info.getArtist());
			map.put("album", mp3Info.getAlbum());
			map.put("displayName", mp3Info.getDisplayName());
			map.put("albumId", String.valueOf(mp3Info.getAlbumId()));
			map.put("duration", formatTime(mp3Info.getDuration()));
			map.put("size", String.valueOf(mp3Info.getSize()));
			map.put("url", mp3Info.getUrl());
			mp3list.add(map);
		}
		return mp3list;
	}
	

	public static String formatTime(long time) {
		String min = time / (1000 * 60) + "";
		String sec = time % (1000 * 60) + "";
		if (min.length() < 2) {
			min = "0" + time / (1000 * 60) + "";
		} else {
			min = time / (1000 * 60) + "";
		}
		if (sec.length() == 4) {
			sec = "0" + (time % (1000 * 60)) + "";
		} else if (sec.length() == 3) {
			sec = "00" + (time % (1000 * 60)) + "";
		} else if (sec.length() == 2) {
			sec = "000" + (time % (1000 * 60)) + "";
		} else if (sec.length() == 1) {
			sec = "0000" + (time % (1000 * 60)) + "";
		}
		return min + ":" + sec.trim().substring(0, 2);
	}
	
	
	 private static final Uri sArtworkUri = Uri.parse("content://media/external/audio/albumart");
	    private static final BitmapFactory.Options sBitmapOptions = new BitmapFactory.Options();

	    public static Bitmap getArtwork(Context context, long song_id, long album_id,
	                                    boolean allowdefault) {
	        if (album_id < 0) {
	            if (song_id >= 0) {
	                Bitmap bm = getArtworkFromFile(context, song_id, -1);
	                if (bm != null) {
	                    return bm;
	                }
	            }
	            if (allowdefault) {
	                return getDefaultArtwork(context);
	            }
	            return null;
	        }
	        ContentResolver res = context.getContentResolver();
	        Uri uri = ContentUris.withAppendedId(sArtworkUri, album_id);
	        if (uri != null) {
	            InputStream in = null;
	            try {
	                in = res.openInputStream(uri);
	                Bitmap bmp = BitmapFactory.decodeStream(in, null, sBitmapOptions);
	                if (bmp == null) {
	                    bmp = getDefaultArtwork(context);
	                }
	                return bmp;
	            } catch (FileNotFoundException ex) {
	                Bitmap bm = getArtworkFromFile(context, song_id, album_id);
	                if (bm != null) {
	                    if (bm.getConfig() == null) {
	                        bm = bm.copy(Bitmap.Config.RGB_565, false);
	                        if (bm == null && allowdefault) {
	                            return getDefaultArtwork(context);
	                        }
	                    }
	                } else if (allowdefault) {
	                    bm = getDefaultArtwork(context);
	                }
	                return bm;
	            } finally {
	                try {
	                    if (in != null) {
	                        in.close();
	                    }
	                } catch (IOException e) {
	                    e.printStackTrace();
	                }
	            }
	        }
	        return null;
	    }

	    private static Bitmap getArtworkFromFile(Context context, long songid, long albumid) {
	        Bitmap bm = null;
	        if (albumid < 0 && songid < 0) {
	            throw new IllegalArgumentException("Must specify an album or a song id");
	        }
	        try {
	            if (albumid < 0) {
	                Uri uri = Uri.parse("content://media/external/audio/media/" + songid + "/albumart");
	                ParcelFileDescriptor pfd = context.getContentResolver()
	                        .openFileDescriptor(uri, "r");
	                if (pfd != null) {
	                    FileDescriptor fd = pfd.getFileDescriptor();
	                    bm = BitmapFactory.decodeFileDescriptor(fd);
	                }
	            } else {
	                Uri uri = ContentUris.withAppendedId(sArtworkUri, albumid);
	                ParcelFileDescriptor pfd = context.getContentResolver()
	                        .openFileDescriptor(uri, "r");
	                if (pfd != null) {
	                    FileDescriptor fd = pfd.getFileDescriptor();
	                    bm = BitmapFactory.decodeFileDescriptor(fd);
	                }
	            }
	        } catch (FileNotFoundException ex) {

	        }
	        return bm;
	    }

	    private static Bitmap getDefaultArtwork(Context context) {
	        BitmapFactory.Options opts = new BitmapFactory.Options();
	        opts.inPreferredConfig = Bitmap.Config.RGB_565;
	        return BitmapFactory.decodeStream(
	                context.getResources().openRawResource(R.drawable.default_album), null,
	                opts);
	    }
}

2.在列表中展示的Activity.

這裡面有兩點要說。一個是因為考慮到一些發燒友歌曲量過大,1000+以上首歌曲,我在載入的時候,使用GifView顯示一張動態的Loading的GIF圖片,提高體驗度。載入要寫非同步任務。

第二點是,因為本地和線上是兩個不同的Service,所以在start其中一個Service的時候,要stop另一個Service,不然若此時線上的Service也在執行,則會出現本地和線上兩首歌同時播放的現象。

ListActivity.java

package com.lzw.activity;


import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.AsyncTask;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.BaseAdapter;
import android.widget.ListView;
import android.widget.TextView;
import com.ant.liao.GifView;
import com.google.gson.Gson;
import com.lzw.bean.SongBean;
import com.lzw.lmusicplayer.R;
import com.lzw.service.NetPlayerService;
import com.lzw.service.PlayerService;
import com.lzw.util.MediaUtil;

import java.util.ArrayList;

public class ListActivity extends Activity implements ListView.OnItemClickListener{

    private ListView musicListView;
    private ArrayList<SongBean> arrayList;
    private MusicListAdapter musicListAdapter;
    private GifView loadingGifView;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_list);
        musicListView= (ListView) this.findViewById(R.id.musiclist);
        loadingGifView= (GifView) this.findViewById(R.id.loadinggif);
        loadingGifView.setGifImage(R.drawable.loading);
        new GetSystemMusicDataTask().execute();
        musicListView.setOnItemClickListener(this);
    }

    @Override
    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
    	Intent intent=new Intent();
    	intent.setClass(ListActivity.this, NetPlayerService.class);
    	intent.setAction("com.lzw.media.NET_MUSIC_SERVICE");
		stopService(intent);
    	
    	Intent intent2=new Intent(ListActivity.this,PlayActivity.class);
        intent2.putExtra("position",position);
        startActivity(intent2);
    }

    public class GetSystemMusicDataTask extends AsyncTask<Void,Void,Void>{

    	private String musicjsonstr;
        @Override
        protected Void doInBackground(Void... params) {
        	arrayList=MediaUtil.getAllSongs(ListActivity.this);
            return null;
        }

        @Override
        protected void onPreExecute() {
            arrayList=new ArrayList<SongBean>();
            loadingGifView.showAnimation();
        }

        @Override
        protected void onPostExecute(Void aVoid) {
            loadingGifView.clearAnimation();
            loadingGifView.setVisibility(View.GONE);
            musicListAdapter=new MusicListAdapter(arrayList);
            musicListView.setAdapter(musicListAdapter);
            
        }
    }

    public class MusicListAdapter extends BaseAdapter{

        private ArrayList<SongBean> musicBeanArrayList;
        
        public MusicListAdapter(ArrayList arrayList){
            musicBeanArrayList=arrayList;
        }
        @Override
        public int getCount() {
            return musicBeanArrayList.size();
        }

        @Override
        public Object getItem(int position) {
            return musicBeanArrayList.get(position);
        }

        @Override
        public long getItemId(int position) {
            return musicBeanArrayList.get(position).getId();
        }

        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            ViewHolder holder = null;
            if(convertView==null){
                convertView= LayoutInflater.from(ListActivity.this).inflate(R.layout.item_song,null);
                holder = new ViewHolder();
                holder.nameTextView= (TextView) convertView.findViewById(R.id.name);
                holder.singerTextView= (TextView) convertView.findViewById(R.id.singer);
                convertView.setTag(holder);
            }else{
                holder = (ViewHolder)convertView.getTag();
            }
            holder.singerTextView.setText(musicBeanArrayList.get(position).getArtist());
            holder.nameTextView.setText(musicBeanArrayList.get(position).getTitle());
            return convertView;
        }
    }
    public static class ViewHolder {
        public TextView nameTextView;
        public TextView singerTextView;
    }
}

3.本地播放的Activity.

PlayActivity.java

在這個Activity裡,通過獲取專輯圖片Bitmap,使用高斯模糊演算法,生成模糊後的背景Bitmap,並設定。

註冊廣播,接受從Service傳來的總時長,當前進度等。

在使用者按下暫定按鈕,上一首,下一首按鈕的時候,給Service發MSG,更新Servie裡的MediaPlayer操作。

package com.lzw.activity;

import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.graphics.Bitmap;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.RelativeLayout;
import android.widget.SeekBar;
import android.widget.SeekBar.OnSeekBarChangeListener;
import android.widget.TextView;
import android.widget.Toast;

import java.util.ArrayList;

import com.lzw.bean.SongBean;
import com.lzw.lmusicplayer.R;
import com.lzw.service.PlayerService;
import com.lzw.util.AppConstantUtil;
import com.lzw.util.GaussianBlurUtil;
import com.lzw.util.MediaUtil;
import com.lzw.view.CircleImageView;

public class PlayActivity extends Activity implements View.OnClickListener {

    private Button mPlayPause;
    private RelativeLayout mBackground ;
	private CircleImageView mAvatar;
	private boolean isPlaying; 
	private boolean isPause;
    private Button mNext;
    private Button mPrevious;
    private Bitmap mResource;
	private static int mCurrentPosition=-1;
	private Boolean flag;
	private String url;
	private SongBean mSongBean;
	private ArrayList<SongBean> musicInfos;
	private TextView nameTextView,singerTextView,currentProgress,finalProgress;
	private SeekBar music_progressBar; 
	private int currentTime;
	private PlayerReceiver playerReceiver;
	public static final String UPDATE_ACTION = "com.lzw.action.UPDATE_ACTION";
	public static final String CTL_ACTION = "com.lzw.action.CTL_ACTION"; 
	public static final String MUSIC_CURRENT = "com.lzw.action.MUSIC_CURRENT"; 
	public static final String MUSIC_DURATION = "com.lzw.action.MUSIC_DURATION";
	public static final String MUSIC_PLAYING = "com.lzw.action.MUSIC_PLAYING";
	
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_play);
        Intent intent=getIntent();
        int position=intent.getIntExtra("position", -1);
        if(position!=mCurrentPosition){
        	mCurrentPosition=position;
        	flag=true;
        	isPause=false;
        	isPlaying=true;
        }else {
			flag=false;
			isPlaying=true;
			isPause=false;
		}
        musicInfos=MediaUtil.getAllSongs(this);
        mSongBean=musicInfos.get(mCurrentPosition);
        mPlayPause = (Button) findViewById(R.id.btn_play_pause);
        music_progressBar=(SeekBar) this.findViewById(R.id.audioTrack);
        mBackground = (RelativeLayout) findViewById(R.id.bg);
		mAvatar = (CircleImageView) findViewById(R.id.avatar);
		nameTextView=(TextView) this.findViewById(R.id.name);
		singerTextView=(TextView) this.findViewById(R.id.singer);
		currentProgress = (TextView) findViewById(R.id.current_progress);
		finalProgress = (TextView) findViewById(R.id.final_progress);
        mPlayPause.setOnClickListener(this);
        mNext = (Button) findViewById(R.id.btn_next);
        mNext.setOnClickListener(this);
        mPrevious = (Button) findViewById(R.id.btn_previous);
        mPrevious.setOnClickListener(this);
        mResource = MediaUtil.getArtwork(this, mSongBean.getId(), mSongBean.getAlbumId(),true);
        setViewContent(mResource);
        nameTextView.setText(mSongBean.getTitle());
        singerTextView.setText(mSongBean.getArtist());
        music_progressBar.setMax((int) mSongBean.getDuration());
        finalProgress.setText(MediaUtil.formatTime(mSongBean.getDuration()));
        music_progressBar.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {
			
			@Override
			public void onStopTrackingTouch(SeekBar seekBar) {
				// TODO Auto-generated method stub
				
			}
			
			@Override
			public void onStartTrackingTouch(SeekBar seekBar) {
				// TODO Auto-generated method stub
				
			}
			
			@Override
			public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
				// TODO Auto-generated method stub
				if (fromUser) {
					mPlayPause.setBackgroundResource(R.drawable.fm_btn_pause);
					isPlaying=true;
					isPause=false;
					audioTrackChange(progress); 
				}
			}
		});
        playerReceiver = new PlayerReceiver();
		IntentFilter filter = new IntentFilter();
		filter.addAction(UPDATE_ACTION);
		filter.addAction(MUSIC_CURRENT);
		filter.addAction(MUSIC_DURATION);
		
		registerReceiver(playerReceiver, filter);
		
		if(flag){
			play();
			isPlaying=true;
			isPause=false;
		}else{
			Intent intent2=new Intent(this,PlayerService.class);
			intent2.putExtra("MSG", AppConstantUtil.PlayerMsg.PLAYING_MSG);
			intent2.putExtra("position", mCurrentPosition);
			intent2.setAction("com.lzw.media.MUSIC_SERVICE");
			startService(intent2);
			isPlaying=true;
	    	isPause=false;
		}
		if(isPause){
			mPlayPause.setBackgroundResource(R.drawable.fm_btn_play);
		}else{
			mPlayPause.setBackgroundResource(R.drawable.fm_btn_pause);
		}
    }

    public void setViewContent(Bitmap bitmap){
		setBackgroundBitmap(bitmap);
		setAvatarBitmap(bitmap);
	}
    
    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.btn_play_pause:
         
                if(isPlaying){
                	pause();
                }else if (isPause){
                	resume();
                }else{
                	play();
                	
                }
                break;

            case R.id.btn_previous:
            	mCurrentPosition--;
                if(mCurrentPosition>=0) {
                	mSongBean=musicInfos.get(mCurrentPosition);
                	nameTextView.setText(mSongBean.getTitle());
                    singerTextView.setText(mSongBean.getArtist());
                    music_progressBar.setProgress(0);
                    mResource = MediaUtil.getArtwork(this, mSongBean.getId(), mSongBean.getAlbumId(), true);
                    previous(mResource);
                    if (isPlaying) {
                        mPlayPause.setBackgroundResource(R.drawable.fm_btn_pause);
                    } else {
                        mPlayPause.setBackgroundResource(R.drawable.fm_btn_play);
                    }
                }else {
                    mCurrentPosition=0;
                    Toast.makeText(PlayActivity.this, "沒有上一首了", Toast.LENGTH_SHORT).show();
                }
                break;

            case R.id.btn_next:
            	mCurrentPosition++;
                if(mCurrentPosition<musicInfos.size()) {
                	mSongBean=musicInfos.get(mCurrentPosition);
                	nameTextView.setText(mSongBean.getTitle());
                	music_progressBar.setProgress(0);
                    singerTextView.setText(mSongBean.getArtist());
                    mResource = MediaUtil.getArtwork(this, mSongBean.getId(), mSongBean.getAlbumId(), true);
                    next(mResource);
                    if (isPlaying) {
                        mPlayPause.setBackgroundResource(R.drawable.fm_btn_pause);
                    } else {
                        mPlayPause.setBackgroundResource(R.drawable.fm_btn_play);
                    }
                }else{
                	mCurrentPosition = musicInfos.size() - 1;
        			Toast.makeText(PlayActivity.this, "沒有下一首了", Toast.LENGTH_SHORT)
        					.show();
                }
                break;
            default:
                break;
        }

    }
    public void setBackgroundBitmap(Bitmap bitmap){
		mBackground.setBackgroundDrawable(GaussianBlurUtil.BoxBlurFilter(bitmap));
	}
	
	
	public void play(){
		Intent intent = new Intent();
		intent.setAction("com.lzw.media.MUSIC_SERVICE");
		intent.setClass(this, PlayerService.class);
		intent.putExtra("url", mSongBean.getUrl());
		intent.putExtra("position", mCurrentPosition);
		intent.putExtra("MSG", AppConstantUtil.PlayerMsg.PLAY_MSG);
		startService(intent);
		mPlayPause.setBackgroundResource(R.drawable.fm_btn_pause);
		isPlaying=true;
    	isPause=false;
    	
	}
	
	public void pause(){
		Intent intent=new Intent();
    	intent.setClass(PlayActivity.this, PlayerService.class);
    	intent.setAction("com.lzw.media.MUSIC_SERVICE");
		intent.putExtra("MSG", AppConstantUtil.PlayerMsg.PAUSE_MSG);
		startService(intent);
		isPlaying = false;
		isPause = true;
        mPlayPause.setBackgroundResource(R.drawable.fm_btn_play);

	}
	private void resume(){
		Intent intent=new Intent();
    	intent.setAction("com.lzw.media.MUSIC_SERVICE");
    	intent.setClass(PlayActivity.this, PlayerService.class);
		intent.putExtra("MSG", AppConstantUtil.PlayerMsg.CONTINUE_MSG);
		startService(intent);
		isPause = false;
		isPlaying = true;
        mPlayPause.setBackgroundResource(R.drawable.fm_btn_pause);
	}
	
	public void previous(Bitmap bitmap){

		//pause();
		changeImage(bitmap);
		play();
	}
	
	public void next(Bitmap bitmap) {
		
		//pause();
		changeImage(bitmap);
		play();

	}
	public  void setAvatarBitmap(Bitmap bitmap){
		mAvatar.setImageBitmap(bitmap);
	}

	private void changeImage(final Bitmap bitmap){
		mAvatar.postDelayed(new Runnable() {
			
			@Override
			public void run() {
				setAvatarBitmap(bitmap);
			}
		}, 100);
		mBackground.postDelayed(new Runnable() {
			
			@Override
			public void run() {
				// TODO Auto-generated method stub
				setBackgroundBitmap(bitmap);
			}
		}, 100);
	}
	
	
		public void audioTrackChange(int progress) {
			Intent intent = new Intent();
			intent.setClass(this, PlayerService.class);
			intent.setAction("com.lzw.media.MUSIC_SERVICE");
			intent.putExtra("url", mSongBean.getUrl());
			intent.putExtra("MSG", AppConstantUtil.PlayerMsg.PROGRESS_CHANGE);
			intent.putExtra("position", mCurrentPosition);
			intent.putExtra("progress", progress);
			startService(intent);
		}
		
		public class PlayerReceiver extends BroadcastReceiver {

			@Override
			public void onReceive(Context context, Intent intent) {
				String action = intent.getAction();
				if (action.equals(MUSIC_CURRENT)) {
					currentTime = intent.getIntExtra("currentTime", -1);
					currentProgress.setText(MediaUtil.formatTime(currentTime));
					music_progressBar.setProgress(currentTime);
				} else if (action.equals(MUSIC_DURATION)) {
					int duration = intent.getIntExtra("duration", -1);
					music_progressBar.setMax(duration);
					finalProgress.setText(MediaUtil.formatTime(duration));
				} else if (action.equals(UPDATE_ACTION)) {
					mCurrentPosition = intent.getIntExtra("current", -1);
					mSongBean=musicInfos.get(mCurrentPosition);
					url = mSongBean.getUrl();
					if (mCurrentPosition >= 0) {
						nameTextView.setText(mSongBean.getTitle());
						singerTextView.setText(mSongBean.getArtist());
						mResource = MediaUtil.getArtwork(PlayActivity.this, mSongBean.getId(), mSongBean.getAlbumId(),true);
						setViewContent(mResource);
					}
					if (mCurrentPosition == 0) {
						finalProgress.setText(MediaUtil.formatTime(musicInfos.get(
								mCurrentPosition).getDuration()));
						mPlayPause.setBackgroundResource(R.drawable.fm_btn_play);
						isPause = true;
					}
				}
			}
		}
}


4.PlayerServie.java

這個是實現本地播放的Service;

在Servie裡既要在Handler裡給Activity發廣播,傳遞當前的播放進度和總時長。

又要接受Activity發來的Intent裡的動作訊息,切換播放狀態。

為了實現更新進度,我在Handler裡進行訊息迴圈,每隔1000毫秒給PlayActiviy傳送一次廣播,更新當前的進度。

package com.lzw.service;

import java.util.ArrayList;

import com.lzw.bean.SongBean;
import com.lzw.util.AppConstantUtil;
import com.lzw.util.MediaUtil;

import android.app.Service;
import android.content.Intent;
import android.media.MediaPlayer;
import android.media.MediaPlayer.OnCompletionListener;
import android.media.MediaPlayer.OnPreparedListener;
import android.os.Handler;
import android.os.IBinder;
import android.util.Log;

public class PlayerService extends Service{

	private MediaPlayer mediaPlayer;
	private String path; 			
	private int msg;				
	private boolean isPause; 	
	private int mCurrentPosition;	
	private int currentTime;		
	private int duration;			
	private ArrayList<SongBean> mp3Infos;
	public static final String UPDATE_ACTION = "com.lzw.action.UPDATE_ACTION";	
	public static final String CTL_ACTION = "com.lzw.action.CTL_ACTION";		
	public static final String MUSIC_CURRENT = "com.lzw.action.MUSIC_CURRENT";	
	public static final String MUSIC_DURATION = "com.lzw.action.MUSIC_DURATION";
	
	private Handler handler = new Handler() {
		public void handleMessage(android.os.Message msg) {
			if (msg.what == 1) {
				if(mediaPlayer != null) {
					currentTime = mediaPlayer.getCurrentPosition(); // 獲取當前音樂播放的位置
					Intent intent = new Intent();
					intent.setAction(MUSIC_CURRENT);
					intent.putExtra("currentTime", currentTime);
					sendBroadcast(intent); // 給PlayerActivity傳送廣播
					handler.sendEmptyMessageDelayed(1, 1000);
				}
			}
		};
	};
	
	@Override
	public IBinder onBind(Intent intent) {
		// TODO Auto-generated method stub
		return null;
	}
	@Override
	public void onCreate() {
		super.onCreate();
		Log.d("service", "service created");
		mediaPlayer = new MediaPlayer();
		mp3Infos = MediaUtil.getAllSongs(PlayerService.this);
		mediaPlayer.setOnCompletionListener(new OnCompletionListener() {
			
			@Override
			public void onCompletion(MediaPlayer mp) {
				// TODO Auto-generated method stub
				mCurrentPosition++;
				Log.v("po", mCurrentPosition+"");
				if (mCurrentPosition <= mp3Infos.size() - 1) {
					Intent sendIntent = new Intent(UPDATE_ACTION);
					sendIntent.putExtra("current", mCurrentPosition);
					
					sendBroadcast(sendIntent);
					path = mp3Infos.get(mCurrentPosition).getUrl();
					play(0);
				}else {
					mediaPlayer.seekTo(0);
					mCurrentPosition = 0;
					Intent sendIntent = new Intent(UPDATE_ACTION);
					sendIntent.putExtra("current", mCurrentPosition);
					
					sendBroadcast(sendIntent);
				}
				
				
				
			}
		});
	}
	
	@Override
	public void onStart(Intent intent, int startId) {
		if(intent==null){
			stopSelf();
		}else{
		path = intent.getStringExtra("url");		
		msg = intent.getIntExtra("MSG", 0);		
		mCurrentPosition=intent.getIntExtra("position",-1);
		if (msg == AppConstantUtil.PlayerMsg.PLAY_MSG) {	
			
			play(0);
		} else if (msg == AppConstantUtil.PlayerMsg.PAUSE_MSG) {	
			pause();	
		} else if (msg == AppConstantUtil.PlayerMsg.STOP_MSG) {		
			stop();
		} else if (msg == AppConstantUtil.PlayerMsg.CONTINUE_MSG) {
			resume();	
		} else if (msg == AppConstantUtil.PlayerMsg.PROGRESS_CHANGE) {	
			currentTime = intent.getIntExtra("progress", -1);
			play(currentTime);
		} else if (msg == AppConstantUtil.PlayerMsg.PLAYING_MSG) {
			handler.sendEmptyMessage(1);
		}
		super.onStart(intent, startId);
		}
	}
	

	private void play(int currentTime) {
		try {
			mediaPlayer.reset();
			mediaPlayer.setDataSource(path);
			mediaPlayer.prepare(); 
			mediaPlayer.setOnPreparedListener(new PreparedListener(currentTime));
			handler.sendEmptyMessage(1);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	
	private void pause() {
		if (mediaPlayer != null && mediaPlayer.isPlaying()) {
			mediaPlayer.pause();
			isPause = true;
		}
	}

	private void resume() {
		if (isPause) {
			mediaPlayer.start();
			isPause = false;
		}
	}

	
	private void stop() {
		if (mediaPlayer != null) {
			mediaPlayer.stop();
			try {
				mediaPlayer.prepare(); 
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}
	
	private final class PreparedListener implements OnPreparedListener {
		private int currentTime;

		public PreparedListener(int currentTime) {
			this.currentTime = currentTime;
		}

		@Override
		public void onPrepared(MediaPlayer mp) {
			mediaPlayer.start(); 
			if (currentTime > 0) { 
				mediaPlayer.seekTo(currentTime);
			}
			Intent intent = new Intent();
			intent.setAction(MUSIC_DURATION);
			duration = mediaPlayer.getDuration();
			intent.putExtra("duration", duration);	
			sendBroadcast(intent);
		}
	}
	
	@Override
	public void onDestroy() {
		if (mediaPlayer != null) {
			mediaPlayer.stop();
			mediaPlayer.release();
			mediaPlayer = null;
		}
	}
	
}

5.儲存歌曲實體的Bean

package com.lzw.bean;

import java.io.Serializable;

public class SongBean implements Serializable {
	private long id; 
	private String title; 
	private String album; 
	private long albumId;
	private String displayName; 
	private String artist; 
	private long duration;
	private long size; 
	private String url; 

	public SongBean() {
	}

	public SongBean(long id, String title, String album, long albumId,
			String displayName, String artist, long duration, long size,
			String url, String lrcTitle, String lrcSize) {
		super();
		this.id = id;
		this.title = title;
		this.album = album;
		this.albumId = albumId;
		this.displayName = displayName;
		this.artist = artist;
		this.duration = duration;
		this.size = size;
		this.url = url;
	}


	public long getId() {
		return id;
	}

	public void setId(long id) {
		this.id = id;
	}

	public String getTitle() {
		return title;
	}

	public void setTitle(String title) {
		this.title = title;
	}

	public String getAlbum() {
		return album;
	}

	public void setAlbum(String album) {
		this.album = album;
	}

	

	public long getAlbumId() {
		return albumId;
	}

	public void setAlbumId(long albumId) {
		this.albumId = albumId;
	}

	public String getArtist() {
		return artist;
	}

	public void setArtist(String artist) {
		this.artist = artist;
	}

	public long getDuration() {
		return duration;
	}

	public void setDuration(long duration) {
		this.duration = duration;
	}

	public long getSize() {
		return size;
	}

	public void setSize(long size) {
		this.size = size;
	}

	public String getUrl() {
		return url;
	}

	public void setUrl(String url) {
		this.url = url;
	}

	public String getDisplayName() {
		return displayName;
	}

	public void setDisplayName(String displayName) {
		this.displayName = displayName;
	}
}



本地音樂的關鍵程式碼就是這些。

接下來看線上播放的關鍵部分。

首先,服務端的測試介面是我自己寫的

需要的注意的是,獲得out物件是要在設定了response的編碼後再獲得,一定要注意這一點,不然會出現中文亂碼的情況。

為了下拉重新整理與上拉載入的功能,我設了一個page引數。

Server部分

IMusicList.java

package com.lzw.mobVod.interfac;

import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.google.gson.Gson;
import com.lzw.mobVod.bean.MusicBean;

public class IMusicList extends HttpServlet{

	/* (non-Javadoc)
	 * @see javax.servlet.http.HttpServlet#doGet(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
	 */
	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		// TODO Auto-generated method stub
	}

	/* (non-Javadoc)
	 * @see javax.servlet.http.HttpServlet#doPost(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
	 */
	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		// TODO Auto-generated method stub
		
		resp.setContentType("text/html;charset=UTF-8");
		resp.setCharacterEncoding("UTF-8");
		resp.setHeader("ContentType","text/html;charset=UTF-8");
		req.setCharacterEncoding("UTF-8");
		PrintWriter out=resp.getWriter();
		Gson gson=new Gson();
		ArrayList<MusicBean> arrayList=new ArrayList<>();
		int page=Integer.parseInt(req.getParameter("page"));
		for(int i=10*(page-1);i<10*page;i++) {
			MusicBean bean=new MusicBean();
			bean.setMusic_name("陌生人"+i);
			bean.setMusic_singer("蔡健雅"+i);
			bean.setMusic_id(i+"");
			bean.setMusic_cover_url("http://xxx.xx.xx.xxx:8080/mobVod/img/music_icon.jpg");//改成自己的伺服器地址
			bean.setMusic_url("http://xxx.xx.xx.xx:8080/mobVod/music/hongsegaogenxie.mp3");
			arrayList.add(bean);
		}
		String jsonstr=gson.toJson(arrayList);
		out.print(jsonstr);
	}
}

客戶端接收介面並在XListView中顯示,下拉重新整理與上拉載入

NetPlayActivity.java

package com.lzw.activity;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

import com.android.volley.Request;
import com.android.volley.RequestQueue;
import com.android.volley.Response;
import com.android.volley.VolleyError;
import com.android.volley.toolbox.StringRequest;
import com.android.volley.toolbox.Volley;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import com.lzw.activity.NetPlayActivity.PlayerReceiver;
import com.lzw.bean.NetSongBean;
import com.lzw.lmusicplayer.R;
import com.lzw.service.PlayerService;
import com.lzw.util.AppConstantUtil;
import com.lzw.view.XListView;
import com.lzw.view.XListView.IXListViewListener;

import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.BaseAdapter;
import android.widget.TextView;

public class NetListActivity extends Activity{
	
	private XListView musicListView;
	 private ArrayList<NetSongBean> arrayList;
	 private MusicListAdapter musicListAdapter;
	 private int page=1;
	 private final String URL="http://xxx.xx.xx.xxx:8080/mobVod/IMusicList.do";
	 private RequestQueue mRequestQueue;  
	 public static final String MUSIC_DURATION = "com.lzw.action.NET_MUSIC_DURATION";//新音樂長度更新動作
	 private ListReceiver mListReceiver;
	 private Gson gson;
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		// TODO Auto-generated method stub
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_netlist);
        musicListView=(XListView) this.findViewById(R.id.musiclist);
        arrayList=new ArrayList<NetSongBean>();
        gson=new Gson();
        musicListView.setPullLoadEnable(true);
        musicListView.setPullRefreshEnable(true);
        mRequestQueue =  Volley.newRequestQueue(this);
        getNetData();
        musicListView.setXListViewListener(new IXListViewListener() {
			
			@Override
			public void onRefresh() {
				// TODO Auto-generated method stub
				page++;
				getNetData();
			}
			
			@Override
			public void onLoadMore() {
				// TODO Auto-generated method stub
				page++;
				getNetData();
				musicListView.smoothScrollToPosition(musicListView.getCount() - 1);
				
				
			}
		});
        musicListView.setOnItemClickListener(new OnItemClickListener() {

			@Override
			public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
				// TODO Auto-generated method stub
				Intent intent=new Intent();
		    	intent.setClass(NetListActivity.this, PlayerService.class);
		    	intent.setAction("com.lzw.media.MUSIC_SERVICE");
				stopService(intent);
				
				Intent intent2=new Intent(NetListActivity.this,NetPlayActivity.class);
				intent2.putExtra("netmusicitem", arrayList.get(position-1));
				intent2.putExtra("position", position-1);
				startActivity(intent2);
		
			}
		});
        mListReceiver = new ListReceiver();
		IntentFilter filter = new IntentFilter();
		filter.addAction(MUSIC_DURATION);
		registerReceiver(mListReceiver, filter);
        
	}
	private void onLoad() {
	        musicListView.stopRefresh();
	        musicListView.stopLoadMore();
	}
	

	
	private void getNetData(){
		RequestQueue requestQueue = Volley.newRequestQueue(getApplicationContext());
		StringRequest stringRequest = new StringRequest(Request.Method.POST,URL,
		    new Response.Listener<String>() {
		        @Override
		        public void onResponse(String response) {
		            Log.d("re", "response -> " + response);
		            arrayList.addAll((ArrayList<NetSongBean>)gson.fromJson(response, new TypeToken<ArrayList<NetSongBean>>(){}.getType()));
		            musicListAdapter=new MusicListAdapter(arrayList);
		            musicListView.setAdapter(musicListAdapter);
		            onLoad();
		        }
		    }, new Response.ErrorListener() {
		        @Override
		        public void onErrorResponse(VolleyError error) {
		            Log.e("er", error.getMessage(), error);
		        }
		    }) {
		    @Override
		    protected Map<String, String> getParams() {
		        //在這裡設定需要post的引數
		              Map<String, String> map = new HashMap<String, String>();  
		            map.put("page", page+"");  
		          return map;
		    }
		};        
		requestQueue.add(stringRequest);
	}

	
	 public class MusicListAdapter extends BaseAdapter{

	        private ArrayList<NetSongBean> musicBeanArrayList;
	        
	        public MusicListAdapter(ArrayList arrayList){
	            musicBeanArrayList=arrayList;
	        }
	        @Override
	        public int getCount() {
	            return musicBeanArrayList.size();
	        }

	        @Override
	        public Object getItem(int position) {
	            return musicBeanArrayList.get(position);
	        }

	        @Override
	        public long getItemId(int position) {
	            return Integer.parseInt(musicBeanArrayList.get(position).getMusic_id());
	        }

	        @Override
	        public View getView(int position, View convertView, ViewGroup parent) {
	            ViewHolder holder = null;
	            if(convertView==null){
	                convertView= LayoutInflater.from(NetListActivity.this).inflate(R.layout.item_song,null);
	                holder = new ViewHolder();
	                holder.nameTextView= (TextView) convertView.findViewById(R.id.name);
	                holder.singerTextView= (TextView) convertView.findViewById(R.id.singer);
	                convertView.setTag(holder);
	            }else{
	                holder = (ViewHolder)convertView.getTag();
	            }
	            holder.singerTextView.setText(musicBeanArrayList.get(position).getMusic_name());
	            holder.nameTextView.setText(musicBeanArrayList.get(position).getMusic_singer());
	            return convertView;
	        }
	    }
	    public static class ViewHolder {
	        public TextView nameTextView;
	        public TextView singerTextView;
	    }
	    
	    
	    public class ListReceiver extends BroadcastReceiver{

			@Override
			public void onReceive(Context context, Intent intent) {
				// TODO Auto-generated method stub
				String action=intent.getAction();
				if(action.equals(MUSIC_DURATION)){
					int pos=intent.getIntExtra("pos", -1);
					int dura=intent.getIntExtra("duration", 1);
					if(pos>0&&dura>0){
						arrayList.get(pos).setDuration(dura);
					}
				}
			}
	    	
	    }
}


可以發現,歌曲的時長在接口裡的json中並沒有資料,我通過在Service播放一首歌時,MediaPlayer獲得當前播放歌曲的時長,傳送廣播,讓兩個NetPlayActivity和NetListActivity都接受到,在播放介面的NetPlayActivity裡收到歌曲市場後,設定Textview的text值,同時為了保證在播放過程中下一次點同一個Postion能跳轉到之前的播放介面,讓資料保持之前的狀態,在ListActivity收到廣播後,更新對應的NetSongBean的duartion屬性。

儲存網路線上歌曲資訊的實體Bean

NetSongBean.java

package com.lzw.bean;

import java.io.Serializable;

public class NetSongBean implements Serializable {

	private String music_id;
	public String getMusic_id() {
		return music_id;
	}
	public void setMusic_id(String music_id) {
		this.music_id = music_id;
	}
	public String getMusic_name() {
		return music_name;
	}
	public void setMusic_name(String music_name) {
		this.music_name = music_name;
	}
	public String getMusic_cover_url() {
		return music_cover_url;
	}
	public void setMusic_cover_url(String music_cover_url) {
		this.music_cover_url = music_cover_url;
	}
	public String getMusic_url() {
		return music_url;
	}
	public void setMusic_url(String music_url) {
		this.music_url = music_url;
	}
	public String getMusic_singer() {
		return music_singer;
	}
	public void setMusic_singer(String music_singer) {
		this.music_singer = music_singer;
	}
	private String music_name;
    private String music_cover_url;
    private String music_url;
    private String music_singer;
    private int duration=-1;
    public void setDuration(int duration) {
		this.duration = duration;
	}
    public int getDuration() {
		return duration;
	}
    
	
}

接下來就是最關鍵的NetPlayService,實現了線上播放音樂的Service.

NetPlayService.java

這個Servce實現了介面OnBufferingUpdateListener。

當網路音訊開始載入的時候,每次更新一次進度,會在回掉函式裡更新一次當前的百分比。此時Service給Activity傳送廣播,根據緩衝百分比,歌曲總時長,來設定SeekBar的SecondaryProgress的值。同時,Servie裡接受使用者拖動進度條後的Progress值,Activity發給Service,Servie收到後,判斷這個值是否在已緩衝的範圍內,如果在的話,mediaplayer.seekto一下。實現拖動進度播放。

package com.lzw.service;

import java.io.IOException;
import java.util.Timer;
import java.util.TimerTask;

import com.lzw.util.AppConstantUtil;

import android.R.integer;
import android.app.Service;
import android.content.Intent;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.media.MediaPlayer.OnBufferingUpdateListener;
import android.media.MediaPlayer.OnCompletionListener;
import android.media.MediaPlayer.OnPreparedListener;
import android.os.Handler;
import android.os.IBinder;
import android.util.Log;

public class NetPlayerService extends Service implements OnBufferingUpdateListener, OnCompletionListener,
OnPreparedListener {

	public MediaPlayer mediaPlayer;
	private int currentTime;
	private int duration;		
	private int mCurrentPosition;
	private int msg;
	private boolean isPause;
	private String url;
	private int percent;
	public static final String MUSIC_CURRENT = "com.lzw.action.NET_MUSIC_CURRENT";	
	public static final String MUSIC_DURATION = "com.lzw.action.NET_MUSIC_DURATION";
	public static final String MUSIC_PERCENT="com.lzw.action.NET_MUSIC_PERCENT";
	
	
	private Handler handler = new Handler() {
		public void handleMessage(android.os.Message msg) {
			if (msg.what == 0) {
				if(mediaPlayer != null) {
					currentTime = mediaPlayer.getCurrentPosition(); 
					Intent intent = new Intent();
					intent.setAction(MUSIC_CURRENT);
					intent.putExtra("currentTime", currentTime);
					sendBroadcast(intent); 
					handler.sendEmptyMessageDelayed(0, 1000);
				}
			}
			if(msg.what==1){
				duration = mediaPlayer.getDuration();
				if (duration > 0) {
					Intent intent = new Intent();
					intent.setAction(MUSIC_DURATION);
					intent.putExtra("pos", mCurrentPosition);
					Log.v("DUA", duration+"");
					intent.putExtra("duration", duration);
					sendBroadcast(intent); 
				}
			}
			if(msg.what==2){
				Intent intent=new Intent();
				intent.setAction(MUSIC_PERCENT);
				intent.putExtra("percent", percent);
				sendBroadcast(intent);
			}
		};
	};
	
	
	@Override
	public void onDestroy() {
		// TODO Auto-generated method stub
		super.onDestroy();
		if (mediaPlayer != null) {
			mediaPlayer.stop();
			mediaPlayer.release();
			mediaPlayer = null;
		}		
	}

	@Override
	public void onCreate() {
		// TODO Auto-generated method stub
		super.onCreate();
		try {
			mediaPlayer = new MediaPlayer();
			mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
			mediaPlayer.setOnBufferingUpdateListener(this);
			mediaPlayer.setOnPreparedListener(this);
		} catch (Exception e) {
			e.printStackTrace();
		}

		
	}
	
	private void play(int currentTime) {
		try {
			mediaPlayer.reset();
			mediaPlayer.setDataSource(url); 
			mediaPlayer.prepare(); 
			mediaPlayer.setOnPreparedListener(this);
			handler.sendEmptyMessage(0);
			handler.sendEmptyMessage(1);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	@Override
	public void onStart(Intent intent, int flags) {
		// TODO Auto-generated method stub
		if(intent==null){
			stopSelf();
		}
		url=intent.getStringExtra("url");
		msg = intent.getIntExtra("MSG", 0);	
		mCurrentPosition=intent.getIntExtra("position",-1);
		if (msg == AppConstantUtil.PlayerMsg.PLAY_MSG) {	
			
			play(0);
		} else if(msg==AppConstantUtil.PlayerMsg.PROGRESS_CHANGE){
			currentTime = intent.getIntExtra("progress", -1);
			if(currentTime>0&¤tTime<=(percent*duration/100)){
				mediaPlayer.seekTo(currentTime);
				handler.sendEmptyMessage(1);
				//play(currentTime);
			}
		}else if (msg == AppConstantUtil.PlayerMsg.PLAYING_MSG) {
			handler.sendEmptyMessage(0);
		}else if (msg == AppConstantUtil.PlayerMsg.PAUSE_MSG) {	
			pause();	
		} else if (msg == AppConstantUtil.PlayerMsg.STOP_MSG) {	
			stop();
		} else if (msg == AppConstantUtil.PlayerMsg.CONTINUE_MSG) {	
			resume();	
		}
		return;
	}

	private void pause() {
		if (mediaPlayer != null && mediaPlayer.isPlaying()) {
			mediaPlayer.pause();
			isPause = true;
		}
	}

	private void resume() {
		if (isPause) {
			mediaPlayer.start();
			isPause = false;
		}
	}

	/**
	 * 停止音樂
	 */
	private void stop() {
		if (mediaPlayer != null) {
			mediaPlayer.stop();
			try {
				mediaPlayer.prepare(); 
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}
	
	@Override
	public IBinder onBind(Intent intent) {
		// TODO Auto-generated method stub
		return null;
	}


		@Override
		public void onPrepared(MediaPlayer mp) {
			mediaPlayer.start();
			Intent intent = new Intent();
			intent.setAction(MUSIC_DURATION);
			duration = mediaPlayer.getDuration();
			intent.putExtra("duration", duration);	
			Log.v("duran", duration+"");
			sendBroadcast(intent);
		}

		@Override
		public void onCompletion(MediaPlayer mp) {
			Log.e("mediaPlayer", "onCompletion");
		}

		@Override
		public void onBufferingUpdate(MediaPlayer mp, int perc) {
			percent=perc;
			handler.sendEmptyMessage(2);
		}

}


線上播放介面

NetPlayActivity.java

接收廣播與傳送廣播。

package com.lzw.activity;

import com.android.volley.RequestQueue;
import com.android.volley.Response;
import com.android.volley.VolleyError;
import com.android.volley.toolbox.ImageRequest;
import com.android.volley.toolbox.Volley;
import com.bumptech.glide.Glide;
import com.bumptech.glide.load.Transformation;
import com.bumptech.glide.request.animation.GlideAnimation;
import com.bumptech.glide.request.target.SimpleTarget;
import com.lzw.activity.PlayActivity.PlayerReceiver;
import com.lzw.bean.NetSongBean;
import com.lzw.lmusicplayer.R;
import com.lzw.service.NetPlayerService;
import com.lzw.service.PlayerService;
import com.lzw.util.AppConstantUtil;
import com.lzw.util.GaussianBlurUtil;
import com.lzw.util.MediaUtil;
import com.lzw.util.NetPlayerUtil;
import com.lzw.view.CircleImageView;

import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.graphics.drawable.BitmapDrawable;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.support.v4.widget.SimpleCursorAdapter.ViewBinder;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.RelativeLayout;
import android.widget.SeekBar;
import android.widget.TextView;
import android.widget.SeekBar.OnSeekBarChangeListener;
import android.widget.Toast;


public class NetPlayActivity extends Activity implements OnClickListener{
	private static int mCurrentPosition=-1;
	private Boolean flag;
	private Button playBtn;
	private RelativeLayout mBackground;
	private CircleImageView mAvatar;
	private SeekBar musicProgress;
	private RequestQueue mQueue;
	private boolean isPlaying; 
	private boolean isPause; 
	private NetSongBean mNetSongBean;
	private int currentTime;
	private TextView nameTextView,singerTextView,currentProgress,finalProgress;
	public static final String UPDATE_ACTION = "com.lzw.action.NET_UPDATE_ACTION"; 
	public static final String CTL_ACTION = "com.lzw.action.NET_CTL_ACTION"; 
	public static final String MUSIC_CURRENT = "com.lzw.action.NET_MUSIC_CURRENT";	
	public static final String MUSIC_DURATION = "com.lzw.action.NET_MUSIC_DURATION";
	public static final String MUSIC_PERCENT="com.lzw.action.NET_MUSIC_PERCENT";
	private PlayerReceiver playerReceiver;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_netplay);
		playBtn = (Button) findViewById(R.id.btn_online_play);
		mBackground = (RelativeLayout) findViewById(R.id.bg);
		mAvatar = (CircleImageView) findViewById(R.id.avatar);
		nameTextView=(TextView) this.findViewById(R.id.name);
		singerTextView=(TextView) this.findViewById(R.id.singer);
		currentProgress = (TextView) findViewById(R.id.current_progress);
		finalProgress = (TextView) findViewById(R.id.final_progress);
		musicProgress = (SeekBar) findViewById(R.id.audioTrack);
		Intent intent=getIntent();
		mNetSongBean=(NetSongBean) intent.getSerializableExtra("netmusicitem");
		int position=intent.getIntExtra("position", -1);
		
		
		
		
		
		if(isPlaying){
	        if(position!=mCurrentPosition){
	        	mCurrentPosition=position;
	        	flag=true;
	        	isPlaying=true;
	        	isPause=false;
	        }else {
				flag=false;
				isPause=false;
				isPlaying=true;
			}
		}else{
			if(position!=mCurrentPosition){
	        	mCurrentPosition=position;
	        	flag=true;
	        	isPlaying=true;
	        	isPause=false;
	        }else {
				flag=false;
				isPause=true;
				isPlaying=false;
			}
		}
		nameTextView.setText(mNetSongBean.getMusic_name());
		singerTextView.setText(mNetSongBean.getMusic_singer());
		playBtn.setOnClickListener(this);
		musicProgress.setOnSeekBarChangeListener(new SeekBarChangeEvent());
		if(mNetSongBean.getDuration()>0){
			finalProgress.setText(MediaUtil.formatTime(mNetSongBean.getDuration()));
			musicProgress.setMax(mNetSongBean.getDuration());
		}
		Glide.with(this).load(mNetSongBean.getMusic_cover_url()).into(mAvatar);
		mQueue=Volley.newRequestQueue(this);
		mBackground.postDelayed(new Runnable() {
			
			@Override
			public void run() {
				// TODO Auto-generated method stub
				ImageRequest imageRequest = new ImageRequest(  
				        mNetSongBean.getMusic_cover_url(),  
				        new Response.Listener<Bitmap>() {  
				            @SuppressWarnings("deprecation")
							@Override  
				            public void onResponse(Bitmap response) {  
				            	//Glide.with(NetPlayActivity.this).load(mNetSongBean.getMusic_cover_url()).into(mAvatar);
				            	mBackground.setBackgroundDrawable(GaussianBlurUtil.BoxBlurFilter(response));
				            }  
				        }, 0, 0, Config.RGB_565, new Response.ErrorListener() {  
				            @Override  
				            public void onErrorResponse(VolleyError error) {  
				            	
				            }  
				        });  
				mQueue.add(imageRequest);  
			}
		}, 1500);
		playerReceiver = new PlayerReceiver();
		IntentFilter filter = new IntentFilter();
		filter.addAction(UPDATE_ACTION);
		filter.addAction(MUSIC_CURRENT);
		filter.addAction(MUSIC_DURATION);
		filter.addAction(MUSIC_PERCENT);
		registerReceiver(playerReceiver, filter);
		if(flag){
			play();
			isPlaying=true;
			isPause=false;
		}else{
			isPlaying=true;
	    	isPause=false;
		}
		if(isPause){
			playBtn.setBackgroundResource(R.drawable.fm_btn_play);
		}else{
			playBtn.setBackgroundResource(R.drawable.fm_btn_pause);
		}
	}
	
	public class PlayerReceiver extends BroadcastReceiver {

		@Override
		public void onReceive(Context context, Intent intent) {
			String action = intent.getAction();
			if (action.equals(MUSIC_CURRENT)) {
				currentTime = intent.getIntExtra("currentTime", -1);
				currentProgress.setText(MediaUtil.formatTime(currentTime));
				musicProgress.setProgress(currentTime);
			} else if (action.equals(MUSIC_DURATION)) {
				int duration = intent.getIntExtra("duration", -1);
				Log.v("dura", duration+"");
				musicProgress.setMax(duration);
				if(mNetSongBean.getDuration()==-1){
					mNetSongBean.setDuration(duration);
				}
				finalProgress.setText(MediaUtil.formatTime(duration));			
			}else if(action.equals(MUSIC_PERCENT)){
				int percent=intent.getIntExtra("percent",-1);
				musicProgress.setSecondaryProgress(musicProgress.getMax()*percent/100);
				
			}
		}
	}

	private void play(){
		Intent intent = new Intent();
		intent.setAction("com.lzw.media.NET_MUSIC_SERVICE");
		intent.setClass(this,NetPlayerService.class);
		intent.putExtra("url", mNetSongBean.getMusic_url());
		intent.putExtra("position", mCurrentPosition);
		intent.putExtra("MSG", AppConstantUtil.PlayerMsg.PLAY_MSG);
		startService(intent);
		isPlaying=true;
    	isPause=false;
	}
	

	class SeekBarChangeEvent implements OnSeekBarChangeListener {

		@Override
		public void onProgressChanged(SeekBar seekBar, int progre,
				boolean fromUser) {
			
			currentTime=progre; 
		}

		@Override
		public void onStartTrackingTouch(SeekBar seekBar) {

		}

		@Override
		public void onStopTrackingTouch(SeekBar seekBar) {
			
			Intent intent = new Intent();
			intent.setClass(NetPlayActivity.this, NetPlayerService.class);
			intent.setAction("com.lzw.media.NET_MUSIC_SERVICE");
			intent.putExtra("url", mNetSongBean.getMusic_url());
			intent.putExtra("MSG", AppConstantUtil.PlayerMsg.PROGRESS_CHANGE);
			intent.putExtra("position", mCurrentPosition);
			intent.putExtra("progress", currentTime);
			startService(intent);
		}

	}

	
	@Override
	protected void onDestroy() {
		super.onDestroy();
		
	}
	
	public void pause(){
		Intent intent=new Intent();
    	intent.setClass(NetPlayActivity.this, NetPlayerService.class);
    	intent.setAction("com.lzw.media.NET_MUSIC_SERVICE");
		intent.putExtra("MSG", AppConstantUtil.PlayerMsg.PAUSE_MSG);
		startService(intent);
		isPlaying = false;
		isPause = true;
        playBtn.setBackgroundResource(R.drawable.fm_btn_play);

	}
	private void resume(){
		Intent intent=new Intent();
    	intent.setAction("com.lzw.media.NET_MUSIC_SERVICE");
    	intent.setClass(NetPlayActivity.this, NetPlayerService.class);
		intent.putExtra("MSG", AppConstantUtil.PlayerMsg.CONTINUE_MSG);
		startService(intent);
		isPause = false;
		isPlaying = true;
        playBtn.setBackgroundResource(R.drawable.fm_btn_pause);
	}

	@Override
	public void onClick(View v) {
		switch (v.getId()) {
		case R.id.btn_online_play:
			 if(isPlaying&&!isPause){
             	pause();
             	Log.v("clickpause", isPlaying+""+isPause);
             }else if (isPause&&!isPlaying){
             	resume();
             	Log.v("clickresume", isPlaying+""+isPause);
             }else{
            	 Log.v("clickplay", isPlaying+""+isPause);
             	play();
             	
             }
             break;
		}
	}

}


整個做法大體就是這樣了,最後放一個高斯模糊演算法。

package com.lzw.util;

import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.PixelFormat;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;

public class GaussianBlurUtil {
	private static float hRadius = 10;
	private static float vRadius = 10;
	private static int iterations = 7;
	
    public static Drawable BoxBlurFilter(Bitmap bmp) {
        int width = bmp.getWidth();
        int height = bmp.getHeight();
        int[] inPixels = new int[width * height];
        int[] outPixels = new int[width * height];
        Bitmap bitmap = Bitmap.createBitmap(width, height,Bitmap.Config.ARGB_8888);
        bmp.getPixels(inPixels, 0, width, 0, 0, width, height);
        for (int i = 0; i < iterations; i++) {
            blur(inPixels, outPixels, width, height, hRadius);
            blur(outPixels, inPixels, height, width, vRadius);
        }
        blurFractional(inPixels, outPixels, width, height, hRadius);
        blurFractional(outPixels, inPixels, height, width, vRadius);
        bitmap.setPixels(inPixels, 0, width, 0, 0, width, height);
        Drawable drawable = new BitmapDrawable(bitmap);
        return drawable;
    }
    
    public static Bitmap BoxBlurFilterBitmap(Bitmap bmp) {
        int width = bmp.getWidth();
        int height = bmp.getHeight();
        int[] inPixels = new int[width * height];
        int[] outPixels = new int[width * height];
        Bitmap bitmap = Bitmap.createBitmap(width, height,Bitmap.Config.ARGB_8888);
        bmp.getPixels(inPixels, 0, width, 0, 0, width, height);
        for (int i = 0; i < iterations; i++) {
            blur(inPixels, outPixels, width, height, hRadius);
            blur(outPixels, inPixels, height, width, vRadius);
        }
        blurFractional(inPixels, outPixels, width, height, hRadius);
        blurFractional(outPixels, inPixels, height, width, vRadius);
        bitmap.setPixels(inPixels, 0, width, 0, 0, width, height);
        return bitmap;
    }


	public static void blur(int[] in, int[] out, int width, int height,
            float radius) {
        int widthMinus1 = width - 1;
        int r = (int) radius;
        int tableSize = 2 * r + 1;
        int divide[] = new int[256 * tableSize];
 
        for (int i = 0; i < 256 * tableSize; i++)
            divide[i] = i / tableSize;
 
        int inIndex = 0;
 
        for (int y = 0; y < height; y++) {
            int outIndex = y;
            int ta = 0, tr = 0, tg = 0, tb = 0;
 
            for (int i = -r; i <= r; i++) {
                int rgb = in[inIndex + clamp(i, 0, width - 1)];
                ta += (rgb >> 24) & 0xff;
                tr += (rgb >> 16) & 0xff;
                tg += (rgb >> 8) & 0xff;
                tb += rgb & 0xff;
            }
 
            for (int x = 0; x < width; x++) {
                out[outIndex] = (divide[ta] << 24) | (divide[tr] << 16)
                        | (divide[tg] << 8) | divide[tb];
 
                int i1 = x + r + 1;
                if (i1 > widthMinus1)
                    i1 = widthMinus1;
                int i2 = x - r;
                if (i2 < 0)
                    i2 = 0;
                int rgb1 = in[inIndex + i1];
                int rgb2 = in[inIndex + i2];
 
                ta += ((rgb1 >> 24) & 0xff) - ((rgb2 >> 24) & 0xff);
                tr += ((rgb1 & 0xff0000) - (rgb2 & 0xff0000)) >> 16;
                tg += ((rgb1 & 0xff00) - (rgb2 & 0xff00)) >> 8;
                tb += (rgb1 & 0xff) - (rgb2 & 0xff);
                outIndex += height;
            }
            inIndex += width;
        }
    }
 
    public static void blurFractional(int[] in, int[] out, int width,
            int height, float radius) {
        radius -= (int) radius;
        float f = 1.0f / (1 + 2 * radius);
        int inIndex = 0;
 
        for (int y = 0; y < height; y++) {
            int outIndex = y;
 
            out[outIndex] = in[0];
            outIndex += height;
            for (int x = 1; x < width - 1; x++) {
                int i = inIndex + x;
                int rgb1 = in[i - 1];
                int rgb2 = in[i];
                int rgb3 = in[i + 1];
 
                int a1 = (rgb1 >> 24) & 0xff;
                int r1 = (rgb1 >> 16) & 0xff;
                int g1 = (rgb1 >> 8) & 0xff;
                int b1 = rgb1 & 0xff;
                int a2 = (rgb2 >> 24) & 0xff;
                int r2 = (rgb2 >> 16) & 0xff;
                int g2 = (rgb2 >> 8) & 0xff;
                int b2 = rgb2 & 0xff;
                int a3 = (rgb3 >> 24) & 0xff;
                int r3 = (rgb3 >> 16) & 0xff;
                int g3 = (rgb3 >> 8) & 0xff;
                int b3 = rgb3 & 0xff;
                a1 = a2 + (int) ((a1 + a3) * radius);
                r1 = r2 + (int) ((r