Android开发 本地与在线音乐播放器(基于Service实现)
来源:互联网 发布:ibm人工智能医学 编辑:程序博客网 时间:2024/04/29 22:45
项目里需要做一个类似于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() {@Overridepublic void onStopTrackingTouch(SeekBar seekBar) {// TODO Auto-generated method stub}@Overridepublic void onStartTrackingTouch(SeekBar seekBar) {// TODO Auto-generated method stub}@Overridepublic void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {// TODO Auto-generated method stubif (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() {@Overridepublic void run() {setAvatarBitmap(bitmap);}}, 100);mBackground.postDelayed(new Runnable() {@Overridepublic void run() {// TODO Auto-generated method stubsetBackgroundBitmap(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 {@Overridepublic 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);}}};};@Overridepublic IBinder onBind(Intent intent) {// TODO Auto-generated method stubreturn null;}@Overridepublic void onCreate() {super.onCreate();Log.d("service", "service created");mediaPlayer = new MediaPlayer();mp3Infos = MediaUtil.getAllSongs(PlayerService.this);mediaPlayer.setOnCompletionListener(new OnCompletionListener() {@Overridepublic void onCompletion(MediaPlayer mp) {// TODO Auto-generated method stubmCurrentPosition++;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);}}});}@Overridepublic 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;}@Overridepublic 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);}}@Overridepublic 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) */@Overrideprotected 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) */@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {// TODO Auto-generated method stubresp.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;@Overrideprotected void onCreate(Bundle savedInstanceState) {// TODO Auto-generated method stubsuper.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() {@Overridepublic void onRefresh() {// TODO Auto-generated method stubpage++;getNetData();}@Overridepublic void onLoadMore() {// TODO Auto-generated method stubpage++;getNetData();musicListView.smoothScrollToPosition(musicListView.getCount() - 1);}}); musicListView.setOnItemClickListener(new OnItemClickListener() {@Overridepublic void onItemClick(AdapterView<?> parent, View view, int position, long id) {// TODO Auto-generated method stubIntent 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{@Overridepublic void onReceive(Context context, Intent intent) {// TODO Auto-generated method stubString 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);}};};@Overridepublic void onDestroy() {// TODO Auto-generated method stubsuper.onDestroy();if (mediaPlayer != null) {mediaPlayer.stop();mediaPlayer.release();mediaPlayer = null;}}@Overridepublic void onCreate() {// TODO Auto-generated method stubsuper.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();}}@Overridepublic void onStart(Intent intent, int flags) {// TODO Auto-generated method stubif(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();}}}@Overridepublic IBinder onBind(Intent intent) {// TODO Auto-generated method stubreturn null;}@Overridepublic 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);}@Overridepublic void onCompletion(MediaPlayer mp) {Log.e("mediaPlayer", "onCompletion");}@Overridepublic 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;@Overrideprotected 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() {@Overridepublic void run() {// TODO Auto-generated method stubImageRequest 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 {@Overridepublic 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 {@Overridepublic void onProgressChanged(SeekBar seekBar, int progre,boolean fromUser) {currentTime=progre; }@Overridepublic void onStartTrackingTouch(SeekBar seekBar) {}@Overridepublic 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);}}@Overrideprotected 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);}@Overridepublic 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) ((r1 + r3) * radius); g1 = g2 + (int) ((g1 + g3) * radius); b1 = b2 + (int) ((b1 + b3) * radius); a1 *= f; r1 *= f; g1 *= f; b1 *= f; out[outIndex] = (a1 << 24) | (r1 << 16) | (g1 << 8) | b1; outIndex += height; } out[outIndex] = in[width - 1]; inIndex += width; } } public static int clamp(int x, int a, int b) { return (x < a) ? a : (x > b) ? b : x; } public static Bitmap drawableToBitmap(Drawable drawable) { Bitmap bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(),drawable.getIntrinsicHeight(), drawable.getOpacity() != PixelFormat.OPAQUE ? Bitmap.Config.ARGB_8888: Bitmap.Config.RGB_565); Canvas canvas = new Canvas(bitmap); drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight()); drawable.draw(canvas); return bitmap;}}
基本上Android的四大组件在这里全都用上了。
分享一下。工程源码就不传了。
- Android开发 本地与在线音乐播放器(基于Service实现)
- Android 在线音乐播放器
- Android MediaPlayer在线音乐播放器
- Android MediaPlayer在线音乐播放器
- android之在线音乐播放器
- Android 数据抓取——在线音乐播放器的实现
- Android开发之基于Service的音乐播放器
- Android开发之基于Service的音乐播放器
- Android开发之基于Service的音乐播放器
- 一款开源Android在线音乐播放器
- Android播放在线音乐文件
- Android 音乐播放器的开发教程(七)运用Broadcast实现service与activity的通信 ----- 小达
- symbian在线音乐播放器
- 在线音乐播放器
- Jamendo在线音乐播放器
- 在线音乐视频播放器
- ubuntu在线音乐播放器
- Android应用开发--MP3音乐播放器Service实现
- 164 Using the LIST command in Recovery Manager (RMAN), which two pieces of information from the RMAN
- 基于Ubuntu 14.04的iSCSI存储配置--Target创建,Initiator连接
- printf,sprintf,vsprintf 区别
- uid_t gid_t等的定义
- 安装fedora后要做的事情
- Android开发 本地与在线音乐播放器(基于Service实现)
- .net framework4与其client profile版本的区别
- shiro实现动态权限管理
- 铁轨(UVa 514)
- 数据结构和算法学习(11)-哈希表
- 判断Android设备是否拥有Root权限
- 虚函数 http://blog.csdn.net/zhouyayong09/article/details/9100667
- linux 系统睡眠.休眠命令
- C语言字节对齐详解