音乐播放器

案例分析:
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;
 }

}

posted on 2015-08-17 12:18  相伴流年  阅读(109)  评论(0)    收藏  举报

导航