项目里需要做一个类似于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 getAllSongs(Context context) {
Cursor cursor = context.getContentResolver().query(
MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, null, null, null,
MediaStore.Audio.Media.DEFAULT_SORT_ORDER);
ArrayList mp3Infos = new ArrayList();
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> getMusicMaps(
List mp3Infos) {
List> mp3list = new ArrayList>();
for (Iterator iterator = mp3Infos.iterator(); iterator.hasNext();) {
SongBean mp3Info = (SongBean) iterator.next();
HashMap map = new HashMap();
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);
}
}
这里面有两点要说。一个是因为考虑到一些发烧友歌曲量过大,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 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{
private String musicjsonstr;
@Override
protected Void doInBackground(Void... params) {
arrayList=MediaUtil.getAllSongs(ListActivity.this);
return null;
}
@Override
protected void onPreExecute() {
arrayList=new ArrayList();
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 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 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= 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;
}
}
}
}
}
这个是实现本地播放的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 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 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);
}
}
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 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();
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() {
@Override
public void onResponse(String response) {
Log.d("re", "response -> " + response);
arrayList.addAll((ArrayList)gson.fromJson(response, new TypeToken>(){}.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 getParams() {
//在这里设置需要post的参数
Map map = new HashMap();
map.put("page", page+"");
return map;
}
};
requestQueue.add(stringRequest);
}
public class MusicListAdapter extends BaseAdapter{
private ArrayList 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() {
@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) ((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;
}
}
分享一下。工程源码就不传了。