音乐播放器
案例分析:
http://192.168.188.121:8080/musiconline/
com.tarena.entity
Music
id name singer ...
setter/getter
toString
com.tarena.utils
HttpUtils
public static final int METHOD_GET = 1;
public static final int METHOD_POST = 2;
public static HttpEntity getEntity(String uri,List<NameValuePair> params,int method)
public static InputStream getStream(HttpEntity entity)
public static long getLength(HttpEntity entity)
BitmapUtils
public static Bitmap loadBitmap(String path)
public static Bitmap loadBitmap(byte[] data,int width,int height)
public static void save(Bitmap bm,File file)
com.tarena.bll
MusicXmlParser
public ArrayList<Music> parse(InputStream in)
MusicXmlParseBiz extends AsyncTask<String,String,ArrayList<Music>>
public ArrayList<Music> doInBackground(String... params)
public void onPostExecute(ArrayList<Music> result)
public void onUpdateProgress(String... values)
com.tarena.adapter
MusicAdapter extends BaseAdapter
getCount
getItem
getItemId
getView
com.tarena.client
MainActivity
强引用
软引用
SoftReference<T>
构造:SoftReference(T t)
主要方法:
T get()
源对象 : 数据集
目标接口: Adapter (通常直接使用的是Adpater的实现类BaseAdapter)
适配器:
class MyAdapter extends BaseAdapter{
private 数据集 s;
}
------------------------------------------------------------------------------------------------------------------------------
package com.tarena.entity;
public class Music {
private int id;
private String name;
private String artist;
private String album;
private String author;
private String composer;
private String duration;
private int downCount;
private int favCount;
private String musicPath;
private String albumPicPath;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getArtist() {
return artist;
}
public void setArtist(String artist) {
this.artist = artist;
}
public String getAlbum() {
return album;
}
public void setAlbum(String album) {
this.album = album;
}
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
public String getComposer() {
return composer;
}
public void setComposer(String composer) {
this.composer = composer;
}
public String getDuration() {
return duration;
}
public void setDuration(String duration) {
this.duration = duration;
}
public int getDownCount() {
return downCount;
}
public void setDownCount(int downCount) {
this.downCount = downCount;
}
public int getFavCount() {
return favCount;
}
public void setFavCount(int favCount) {
this.favCount = favCount;
}
public String getMusicPath() {
return musicPath;
}
public void setMusicPath(String musicPath) {
this.musicPath = musicPath;
}
public String getAlbumPicPath() {
return albumPicPath;
}
public void setAlbumPicPath(String albumPicPath) {
this.albumPicPath = albumPicPath;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder("音乐信息:\n");
sb.append("编号:").append(id).append('\n');
sb.append("歌名:").append(name).append('\n');
sb.append("歌手:").append(artist).append('\n');
sb.append("专辑:").append(album).append('\n');
sb.append("作词:").append(author).append('\n');
sb.append("作曲:").append(composer).append('\n');
sb.append("时常:").append(duration).append('\n');
sb.append("下载次数:").append(downCount).append('\n');
sb.append("收藏次数:").append(favCount).append('\n');
return sb.toString();
}
}
------------------------------------------------------------------------------------------------------------------------------
package com.tarena.utils;
public class GlobalConsts {
public static final String BASE_URL = "http://192.168.188.121:8080/musiconline/";
}
------------------------------------------------------------------------------------------------------------------------------
package com.tarena.utils;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.params.CoreConnectionPNames;
public class HttpUtils {
public static final int METHOD_GET = 1;
public static final int METHOD_POST = 2;
/**
* 连接服务端指定的资源路径获取响应实体对象
*
* @param uri
* @param params
* @param method
* @return
* @throws IOException
*/
public static HttpEntity getEntity(String uri, List<NameValuePair> params,
int method) throws IOException {
HttpEntity entity = null;
// 创建客户端对象
HttpClient client = new DefaultHttpClient();
client.getParams().setParameter(
CoreConnectionPNames.CONNECTION_TIMEOUT, 3000);
// 创建请求对象
HttpUriRequest request = null;
switch (method) {
case METHOD_GET:// get请求
StringBuilder sb = new StringBuilder(uri);
if (params != null && !params.isEmpty()) {
sb.append('?');
for (NameValuePair pair : params) {
sb.append(pair.getName()).append('=')
.append(pair.getValue()).append('&');
}
sb.deleteCharAt(sb.length() - 1);
}
request = new HttpGet(sb.toString());
break;
case METHOD_POST:// post请求
request = new HttpPost(uri);
if (params != null && !params.isEmpty()) {
UrlEncodedFormEntity reqEntity = new UrlEncodedFormEntity(
params);
((HttpPost) request).setEntity(reqEntity);
}
break;
}
// 执行请求获得实体对象
HttpResponse response = client.execute(request);
if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
entity = response.getEntity();
}
// 返回响应实体
return entity;
}
/**
* 获取指定实体对象的 长度信息
*
* @param entity
* @return
*/
public static long getLength(HttpEntity entity) {
if (entity != null)
return entity.getContentLength();
return 0;
}
/**
* 获取实体输入流
*
* @param entity
* @return
* @throws IOException
* @throws IllegalStateException
*/
public static InputStream getStream(HttpEntity entity)
throws IllegalStateException, IOException {
if (entity != null) {
return entity.getContent();
}
return null;
}
}
------------------------------------------------------------------------------------------------------------------------------
package com.tarena.utils;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import android.graphics.Bitmap;
import android.graphics.Bitmap.CompressFormat;
import android.graphics.BitmapFactory;
import android.graphics.BitmapFactory.Options;
public class BitmapUtils {
/**
* 从指定文件路径 加载位图对象
*
* @param path
* @return
*/
public static Bitmap loadBitmap(String path) {
return BitmapFactory.decodeFile(path);
}
/**
* 从图片的字节数组中 加载位图对象 并对加载图片的宽高进行限制
*
* @param data
* @param width
* @param height
* @return
*/
public static Bitmap loadBitmap(byte[] data, int width, int height) {
Bitmap bm = null;
// 创建加载选项对象
Options opts = new Options();
// 设置仅加载边界信息
opts.inJustDecodeBounds = true;
// 加载为位图尺寸信息
BitmapFactory.decodeByteArray(data, 0, data.length, opts);
// 计算并设置收缩比例
int x = opts.outWidth / width;
int y = opts.outHeight / height;
opts.inSampleSize = x > y ? x : y;
// 取消仅加载边界信息的设置
opts.inJustDecodeBounds = false;
// 加载位图
bm = BitmapFactory.decodeByteArray(data, 0, data.length, opts);
return bm;
}
/**
* 将位图对象保存到指定文件目录
*
* @param bm
* @param file
* @throws IOException
*/
public static void save(Bitmap bm, File file) throws IOException {
if (bm != null && file != null) {
// 如果父目录不存在 则创建目录
if (!file.getParentFile().exists()) {
file.getParentFile().mkdirs();
}
// 如果文件不存在则创建文件
if (!file.exists()) {
file.createNewFile();
}
// 保存
bm.compress(CompressFormat.JPEG, 100, new FileOutputStream(file));
}
}
}
------------------------------------------------------------------------------------------------------------------------------
package com.tarena.bll;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlPullParserFactory;
import com.tarena.entity.Music;
public class MusicXmlParser {
/**
* 解析输入流中的xml数据 并返回解析结果
*
* @param is
* @return
* @throws XmlPullParserException
* @throws IOException
*/
public ArrayList<Music> parse(InputStream is)
throws XmlPullParserException, IOException {
ArrayList<Music> musics = null;
Music m = null;
// 创建解析器对象
XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
XmlPullParser parser = factory.newPullParser();
// 设置输入源
parser.setInput(new InputStreamReader(is));
// 获取当前的事件类型
int eventType = parser.getEventType();
// 当事件类型不等于 END_DOCUMENT时 循环解析
while (eventType != XmlPullParser.END_DOCUMENT) {
// 判断当前事件类型 并执行相应的操作
switch (eventType) {
case XmlPullParser.START_DOCUMENT:// 开始解析xml
musics = new ArrayList<Music>();
break;
case XmlPullParser.START_TAG:// 开始标签
// 获取标签名
String tagName = parser.getName();
// 如果标签名是Music,实例化music对象,设置id
if ("music".equals(tagName)) {
m = new Music();
m.setId(Integer.parseInt(parser.getAttributeValue(null,
"id")));
} else if ("name".equals(tagName)) {
m.setName(parser.nextText());
} else if ("singer".equals(tagName)) {
m.setArtist(parser.nextText());
} else if ("album".equals(tagName)) {
m.setAlbum(parser.nextText());
} else if ("author".equals(tagName)) {
m.setAuthor(parser.nextText());
} else if ("composer".equals(tagName)) {
m.setComposer(parser.nextText());
} else if ("albumpic".equals(tagName)) {
m.setAlbumPicPath(parser.nextText());
} else if ("musicpath".equals(tagName)) {
m.setMusicPath(parser.nextText());
} else if ("time".equals(tagName)) {
m.setDuration(parser.nextText());
} else if ("downCount".equals(tagName)) {
m.setDownCount(Integer.parseInt(parser.nextText()));
} else if ("favCount".equals(tagName)) {
m.setFavCount(Integer.parseInt(parser.nextText()));
}
break;
case XmlPullParser.END_TAG:// 结束标签
if ("music".equals(parser.getName())) {
musics.add(m);
}
break;
}
// 驱动到下一 事件
eventType = parser.next();
}
// 返回解析结果
return musics;
}
}
------------------------------------------------------------------------------------------------------------------------------
package com.tarena.bll;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import org.apache.http.HttpEntity;
import org.xmlpull.v1.XmlPullParserException;
import com.tarena.client.MainActivity;
import com.tarena.entity.Music;
import com.tarena.utils.HttpUtils;
import android.os.AsyncTask;
import android.util.Log;
import android.widget.Toast;
public class MusicXmlParseBiz extends
AsyncTask<String, String, ArrayList<Music>> {
private MainActivity context;
public MusicXmlParseBiz(MainActivity context) {
this.context = context;
}
@Override
protected ArrayList<Music> doInBackground(String... params) {
ArrayList<Music> musics = null;
try {
publishProgress("开始联网解析xml");
HttpEntity entity = HttpUtils.getEntity(params[0], null,
HttpUtils.METHOD_GET);
InputStream is = HttpUtils.getStream(entity);
musics = new MusicXmlParser().parse(is);
} catch (IllegalStateException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (XmlPullParserException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return musics;
}
/**
* 当异步任务执行完成时
*/
@Override
protected void onPostExecute(ArrayList<Music> result) {
// 调用MainActivity的方法 更新listview
context.updateListView(result);
publishProgress("解析结束");
}
@Override
protected void onProgressUpdate(String... values) {
Toast.makeText(context, values[0], Toast.LENGTH_LONG).show();
}
}
------------------------------------------------------------------------------------------------------------------------------
package com.tarena.adapter;
import java.io.File;
import java.io.IOException;
import java.lang.ref.SoftReference;
import java.util.ArrayList;
import java.util.HashMap;
import org.apache.http.HttpEntity;
import org.apache.http.util.EntityUtils;
import com.tarena.client.R;
import com.tarena.entity.Music;
import com.tarena.utils.BitmapUtils;
import com.tarena.utils.GlobalConsts;
import com.tarena.utils.HttpUtils;
import android.content.Context;
import android.graphics.Bitmap;
import android.os.Environment;
import android.os.Handler;
import android.os.Message;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;
public class MusicAdapter extends BaseAdapter {
private ArrayList<Music> musics;
private LayoutInflater inflater;
private ArrayList<ImageLoadTask> tasks;// 任务集合
private Thread workThread;
private boolean isLoop;
private Handler handler;
private HashMap<String, SoftReference<Bitmap>> caches;
private Context context;
public void setMusics(ArrayList<Music> musics) {
if (musics != null)
this.musics = musics;
else
this.musics = new ArrayList<Music>();
}
/**
* 替换适配器中的数据集 并刷新listview
*
* @param musics
*/
public void changeData(ArrayList<Music> musics) {
this.setMusics(musics);
this.notifyDataSetChanged();
}
public MusicAdapter(Context context, ArrayList<Music> musics,
final ListView lvMusics) {
this.context = context;
this.setMusics(musics);
this.inflater = LayoutInflater.from(context);
this.tasks = new ArrayList<MusicAdapter.ImageLoadTask>();
this.caches = new HashMap<String, SoftReference<Bitmap>>();
this.handler = new Handler() {
public void handleMessage(android.os.Message msg) {
// 获取加载完成的图片
ImageLoadTask task = (ImageLoadTask) msg.obj;
// 根据path为tag 从listView中查找imageview
ImageView iv = (ImageView) lvMusics.findViewWithTag(task.path);
// 更新图片框
if (iv != null) {
if (task.bitmap != null)
iv.setImageBitmap(task.bitmap);
else
iv.setImageResource(R.drawable.ic_launcher);
}
};
};
this.isLoop = true;
this.workThread = new Thread() {
public void run() {
while (isLoop) {
// 轮询任务集合
while (!tasks.isEmpty()) {
try {
// 获取第一条任务
ImageLoadTask task = tasks.remove(0);
// 执行图片加载任务
HttpEntity entity = HttpUtils.getEntity(
GlobalConsts.BASE_URL + task.path, null,
HttpUtils.METHOD_GET);
byte[] data = EntityUtils.toByteArray(entity);
task.bitmap = BitmapUtils
.loadBitmap(data, 100, 100);
// 加载成功 发送消息到主线程
Message msg = Message.obtain(handler, 0, task);
msg.sendToTarget();
// 缓存
caches.put(task.path, new SoftReference<Bitmap>(
task.bitmap));
File file = getFile(task.path);
BitmapUtils.save(task.bitmap, file);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
// 线程等待
synchronized (this) {
try {
this.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
};
};
this.workThread.start();
}
@Override
public int getCount() {
// TODO Auto-generated method stub
return musics.size();
}
@Override
public Music getItem(int position) {
// TODO Auto-generated method stub
return musics.get(position);
}
@Override
public long getItemId(int position) {
// TODO Auto-generated method stub
return getItem(position).getId();
}
private File getFile(String path) {
return new File(context.getExternalCacheDir(), path);
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
// 加载或复用item界面
ViewHolder holder = null;
if (convertView == null) {
convertView = inflater.inflate(R.layout.item_music, null);
holder = new ViewHolder();
holder.ivAlbum = (ImageView) convertView.findViewById(R.id.ivAlbum);
holder.tvName = (TextView) convertView.findViewById(R.id.tvName);
holder.tvDuration = (TextView) convertView
.findViewById(R.id.tvDuration);
holder.tvAlbum = (TextView) convertView.findViewById(R.id.tvAlbum);
holder.tvArtist = (TextView) convertView
.findViewById(R.id.tvArtist);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
// 获取指定位置的数据
Music m = getItem(position);
// 将数据写入到item界面
holder.tvName.setText(m.getName());
holder.tvDuration.setText(m.getDuration());
holder.tvArtist.setText(m.getArtist());
holder.tvAlbum.setText(m.getAlbum());
// 加载专辑图片
// 获取图片路径
String path = m.getAlbumPicPath();
// 首先判断内存缓存中是否存在该路径的图片
if (caches.containsKey(path)) {
Bitmap bm = caches.get(path).get();
if (bm != null) {
holder.ivAlbum.setImageBitmap(bm);
return convertView;
} else {
caches.remove(path);
}
}
// 判断是否存在文件缓存
Bitmap bm = BitmapUtils.loadBitmap(getFile(path).getAbsolutePath());
if (bm != null) {
holder.ivAlbum.setImageBitmap(bm);
return convertView;
}
// 设置图片的tag标记为图片路径
holder.ivAlbum.setTag(path);
// 创建图片加载任务
holder.ivAlbum.setImageResource(R.drawable.ic_launcher);
ImageLoadTask task = new ImageLoadTask();
task.path = path;
// 如果任务集合中不存在该任务 则添加到任务集合
if (!tasks.contains(task)) {
tasks.add(task);
synchronized (workThread) {
try {
workThread.notify();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
// 返回item界面
return convertView;
}
class ImageLoadTask {
private String path;
private Bitmap bitmap;
@Override
public boolean equals(Object o) {
ImageLoadTask task = (ImageLoadTask) o;
return this.path.equals(task.path);
}
}
class ViewHolder {
private ImageView ivAlbum;
private TextView tvName;
private TextView tvDuration;
private TextView tvArtist;
private TextView tvAlbum;
}
}
------------------------------------------------------------------------------------------------------------------------------
package com.tarena.client;
import java.util.ArrayList;
import com.tarena.adapter.MusicAdapter;
import com.tarena.bll.MusicXmlParseBiz;
import com.tarena.entity.Music;
import com.tarena.utils.GlobalConsts;
import android.os.Bundle;
import android.app.Activity;
import android.view.Menu;
import android.widget.ListView;
public class MainActivity extends Activity {
private ListView lvMusics;
private MusicAdapter adapter;
/**
* 界面初始化方法
*/
private void setupView() {
// 获取listview的引用
lvMusics = (ListView) findViewById(R.id.lvMusics);
// 创建适配器
adapter = new MusicAdapter(this, null, lvMusics);
// 设置适配器
lvMusics.setAdapter(adapter);
}
/**
* 刷新listView
*
* @param musics
*/
public void updateListView(ArrayList<Music> musics) {
adapter.changeData(musics);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
setupView();// 初始化listview,使用空集合
// 启动异步任务 加载和解析xml
new MusicXmlParseBiz(this)
.execute(GlobalConsts.BASE_URL + "sounds.xml");
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
}
浙公网安备 33010602011771号