ListView异步批量加载图片
单线程轮循机制批量下载图片
例如:imageloader框架底层也是这么实现的!
思路:主线程向任务集合添加一个任务,工作线程从任务集合移除第一个任务,如果有任务一直移除,一直轮循,拿到图片之后解析成Bitmap,呈现的imageView当中。
package com.tarena.musicclient.adapter;
import java.io.IOException;
import java.lang.ref.SoftReference;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import org.apache.http.HttpEntity;
import org.apache.http.util.EntityUtils;
import com.tarena.musicclient.activity.R;
import com.tarena.musicclient.entity.Music;
import com.tarena.musicclient.util.BitmapUtils;
import com.tarena.musicclient.util.GlobalConsts;
import com.tarena.musicclient.util.HttpUtils;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
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 Context context;
private List<Music> musics;
private LayoutInflater inflater;
//(2)声明任务集合
private List<ImageLoadTask> tasks=new ArrayList<ImageLoadTask>();
private ListView listView;
//声明用于轮循任务集合的工作线程
private Thread workThread;
//声明变量控制while循环
private boolean isLoop=true;
//声明缓存集合
private HashMap<String, SoftReference<Bitmap>> cache
=new HashMap<String, SoftReference<Bitmap>>();
//声明Handler 更新ImageView
private Handler handler=new Handler(){
public void handleMessage(android.os.Message msg) {
switch (msg.what) {
case HANDLER_LOAD_IMAGE_SUCCESS:
//给ImageView设置Bitmap
ImageLoadTask task=(ImageLoadTask)msg.obj;
//通过tag寻找到相应的ImageView
ImageView ivAlum=(ImageView)listView.findViewWithTag(task.position);
if(ivAlum!=null){
if(task.bitmap!=null){
ivAlum.setImageBitmap(task.bitmap);
}else{
ivAlum.setImageResource(R.drawable.ic_launcher);
}
}
break;
}
}
};
public static final int HANDLER_LOAD_IMAGE_SUCCESS=0;
public MusicAdapter(Context context, List<Music> musics, ListView listView) {
this.context=context;
this.musics=musics;
this.listView=listView;
inflater=LayoutInflater.from(context);
//(5)MusicAdapter有几个,工作线程就有几个
//对workThread进行初始化
workThread=new Thread(){
public void run() {
//(6)不断轮循任务集合
while(isLoop){
//如果任务集合不是空集
if(!tasks.isEmpty()){
//获取任务对象并且发送请求
ImageLoadTask task = tasks.remove(0);
//通过路径返回Bitmap对象
Bitmap bitmap=loadBitmap(task.path);
task.bitmap=bitmap;
//给相应的ImageView设置Bitmap handler
Message msg=new Message();
msg.what=HANDLER_LOAD_IMAGE_SUCCESS;
msg.obj=task;
handler.sendMessage(msg);
}else{
//同步代码块:一但调用了某个对象的wait()/notify()方法后,外面一定套一个以这个对象为锁的同步代码块
synchronized (workThread) {
//如果任务集合是空集 wait等待
try {
workThread.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
};
workThread.start();
}
/**
* 通过path 获取Bitmap
* @param path
* @return
*/
public Bitmap loadBitmap(String path){
Bitmap bitmap=null;
String uri=GlobalConsts.BASEURL+path;
try {
//实体转成字节数组,字节数组转成图片
HttpEntity entity=HttpUtils.send(HttpUtils.METHOD_GET, uri, null);
byte[] bytes=EntityUtils.toByteArray(entity);
bitmap=BitmapUtils.loadBitmap(bytes, 50, 50);
//向缓存集合中存储缓存图片
cache.put(path, new SoftReference<Bitmap>(bitmap));
} catch (IOException e) {
e.printStackTrace();
}
return bitmap;
}
@Override
public int getCount() {
return musics.size();
}
public Object getItem(int position) {
return musics.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder=null;
if(convertView==null){
convertView=inflater.inflate(R.layout.item_lv_music, null);
holder=new ViewHolder();
holder.ivAlbum=(ImageView)convertView.findViewById(R.id.imageView1);
holder.tvName=(TextView)convertView.findViewById(R.id.tvName);
holder.tvDuration=(TextView)convertView.findViewById(R.id.tvDuration);
holder.tvSinger=(TextView)convertView.findViewById(R.id.tvSinger);
holder.tvAuthor=(TextView)convertView.findViewById(R.id.tvAuthor);
convertView.setTag(holder);
}
holder=(ViewHolder)convertView.getTag();
//给控件赋值
Music music=musics.get(position);
holder.tvName.setText(music.getName());
holder.tvSinger.setText(music.getSinger());
holder.tvAuthor.setText(music.getAuthor());
holder.tvDuration.setText(music.getDurationtime());
//给当前item中的ImageView设置一个Tag
//用于图片下载完成后根据该tag
//找到相应的ImageView
holder.ivAlbum.setTag(position);
//查询缓存中是否有图片 如果有 则直接获取
SoftReference<Bitmap> ref=cache.get(music.getAlbumpic());
if(ref!=null && ref.get()!=null){
Bitmap bitmap=ref.get();
holder.ivAlbum.setImageBitmap(bitmap);
System.out.println("从缓存中读取图片..");
return convertView;
}
//(3)下载一张图片
//向任务队列中添加一个图片任务
ImageLoadTask task=new ImageLoadTask();
//albumPic: images/xxxxx.jpg
task.path=music.getAlbumpic();
task.position=position;
tasks.add(task);
//(4)唤醒工作线程 起来干活
notifyWorkThread();
return convertView;
}
/**
* 唤醒工作线程
*/
public void notifyWorkThread(){
//注意:一但调用wait活notify方法的时候,就要在这个同步代码块对象上加锁
synchronized (workThread) {
workThread.notify();
}
}
//(1)创建图片下载任务类型的类
class ImageLoadTask{
String path;//图片路径
Bitmap bitmap;//图片对象
int position;
}
class ViewHolder{
ImageView ivAlbum;
TextView tvName;
TextView tvDuration;
TextView tvSinger;
TextView tvAuthor;
}
public void stopWorkThread() {
isLoop=false;
notifyWorkThread();
}
}
图片压缩
图片压缩的意义:(像一些小图标,不需要很高清)
例如我们写的上面的程序图片都是从服务器端下载下来的,一个图片大小是5k,但是这个5k的图片加载到内存里就不止是5k了,一个Bitmap肯定比5k要多(5k的十倍)50k,10张就500k(半兆),这样图片多了的话就非常浪费内存,占用内存!当占用内存十分大的时候,android 手机就会出现GC(垃圾回收机制),自动销毁堆内存中的垃圾。如果java管理的内存越来越满,快溢出了,GC执行频率会上升,导致效果:在GC执行垃圾回收的时候,所有的线程暂停,主线程也不准绘制UI!如果GC执行频率非常频繁,肯定会出现吊帧,卡顿的现象!
Bitmap图片(位图对象):
BitmapFactory 图片工厂:
Options封装了创建Bitmap对象时使用的参数
package com.tarena.musicclient.adapter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import org.apache.http.HttpEntity;
import org.apache.http.util.EntityUtils;
import com.tarena.musicclient.activity.R;
import com.tarena.musicclient.entity.Music;
import com.tarena.musicclient.util.BitmapUtils;
import com.tarena.musicclient.util.GlobalConsts;
import com.tarena.musicclient.util.HttpUtils;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
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 Context context;
private List<Music> musics;
private LayoutInflater inflater;
//声明任务集合
private List<ImageLoadTask> tasks=new ArrayList<ImageLoadTask>();
private ListView listView;
//声明用于轮循任务集合的工作线程
private Thread workThread;
//声明Handler 更新ImageView
private Handler handler=new Handler(){
public void handleMessage(android.os.Message msg) {
switch (msg.what) {
case HANDLER_LOAD_IMAGE_SUCCESS:
//给ImageView设置Bitmap
ImageLoadTask task=(ImageLoadTask)msg.obj;
//通过tag寻找到相应的ImageView
ImageView ivAlum=(ImageView)listView.findViewWithTag(task.position);
if(ivAlum!=null){
if(task.bitmap!=null){
ivAlum.setImageBitmap(task.bitmap);
}else{
ivAlum.setImageResource(R.drawable.ic_launcher);
}
}
break;
}
}
};
public static final int HANDLER_LOAD_IMAGE_SUCCESS=0;
public MusicAdapter(Context context, List<Music> musics, ListView listView) {
this.context=context;
this.musics=musics;
this.listView=listView;
inflater=LayoutInflater.from(context);
//对workThread进行初始化
workThread=new Thread(){
public void run() {
//不断轮循任务集合
while(true){
//如果任务集合不是空集
if(!tasks.isEmpty()){
//获取任务对象并且发送请求
ImageLoadTask task = tasks.remove(0);
Bitmap bitmap=loadBitmap(task.path);
task.bitmap=bitmap;
//给相应的ImageView设置Bitmap handler
Message msg=new Message();
msg.what=HANDLER_LOAD_IMAGE_SUCCESS;
msg.obj=task;
handler.sendMessage(msg);
}else{
synchronized (workThread) {
//如果任务集合是空集 wait等待
try {
workThread.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
};
workThread.start();
}
/**
* 通过path 获取Bitmap
* @param path
* @return
*/
public Bitmap loadBitmap(String path){
Bitmap bitmap=null;
String uri=GlobalConsts.BASEURL+path;
try {
HttpEntity entity=HttpUtils.send(HttpUtils.METHOD_GET, uri, null);
byte[] bytes=EntityUtils.toByteArray(entity);
/**
*图片压缩处理,工具类工具方法(传个来字节数字,和宽度、高度)
**/
bitmap=BitmapUtils.loadBitmap(bytes, 50, 50);
} catch (IOException e) {
e.printStackTrace();
}
return bitmap;
}
@Override
public int getCount() {
return musics.size();
}
public Object getItem(int position) {
return musics.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder=null;
if(convertView==null){
convertView=inflater.inflate(R.layout.item_lv_music, null);
holder=new ViewHolder();
holder.ivAlbum=(ImageView)convertView.findViewById(R.id.imageView1);
holder.tvName=(TextView)convertView.findViewById(R.id.tvName);
holder.tvDuration=(TextView)convertView.findViewById(R.id.tvDuration);
holder.tvSinger=(TextView)convertView.findViewById(R.id.tvSinger);
holder.tvAuthor=(TextView)convertView.findViewById(R.id.tvAuthor);
convertView.setTag(holder);
}
holder=(ViewHolder)convertView.getTag();
//给控件赋值
Music music=musics.get(position);
holder.tvName.setText(music.getName());
holder.tvSinger.setText(music.getSinger());
holder.tvAuthor.setText(music.getAuthor());
holder.tvDuration.setText(music.getDurationtime());
//给当前item中的ImageView设置一个Tag
//用于图片下载完成后根据该tag
//找到相应的ImageView
holder.ivAlbum.setTag(position);
//下载一张图片
//向任务队列中添加一个图片任务
ImageLoadTask task=new ImageLoadTask();
//albumPic: images/xxxxx.jpg
task.path=music.getAlbumpic();
task.position=position;
tasks.add(task);
//唤醒工作线程 起来干活
notifyWorkThread();
return convertView;
}
/**
* 唤醒工作线程,起来运行跳出循环
*/
public void notifyWorkThread(){
synchronized (workThread) {
workThread.notify();
}
}
class ImageLoadTask{
String path;
Bitmap bitmap;
int position;
}
class ViewHolder{
ImageView ivAlbum;
TextView tvName;
TextView tvDuration;
TextView tvSinger;
TextView tvAuthor;
}
}
图片压缩工具类
package com.tarena.musicclient.util;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.BitmapFactory.Options;
public class BitmapUtils {
/**
* 通过字节数组解析出Bitmap对象
* 需要按照一定的宽高的规格进行压缩
* @param bytes 数据源
* @param width 图片的目标宽度
* @param height 图片的目标高度
* @return
*/
public static Bitmap loadBitmap(byte[] bytes, int width, int height) {
Options opt=new Options();
//设置是否仅仅加载边界属性
opt.inJustDecodeBounds=true;
BitmapFactory.decodeByteArray(bytes, 0, bytes.length, opt);
//获取图片的原始的高度与宽度
int w=opt.outWidth/width;
int h=opt.outHeight/height;
int scale=w>h ? w : h;
//设置压缩比例
opt.inSampleSize=scale;
//再次进行解析Bitmap
opt.inJustDecodeBounds=false;
return BitmapFactory.decodeByteArray(bytes, 0, bytes.length, opt);
}
}
Android 内存泄漏
Android内存当中有垃圾对象,这些垃圾对象被占用了之后还不能被GC(垃圾回收机制回收)内存也不能重复利用,导致内存泄漏。
GC垃圾回收机制:
项目中内存泄漏中的地方:
解决方法:
在Activity生命周期方法中销毁的时候关闭当前线程,详情看上方代码
内存泄漏最常见的情况:
Thread
new Thread (){}.start()必须给出run方法执行完毕的条件,在应用程序退出的时候销毁工作线程。
查看本程序中运行的线程
Java中的引用
强引用: StrongReference
e=new Emp();
就算出OOM,也不会销毁强引用
软引用: SoftReference
弱java管理的内存接近阈值,将会销毁一些软引用。释放内存
弱引用: WeakReference
就算java管理的内存没有接近阈值,就会销毁一些弱引用。
虚引用: …………
由GC管理的。
软引用的使用:
SoftReference s=new SoftReference(bitmap);
Bitmap bitmap=s.get();
Android图片的内存缓存
第一次把图片下载到手机后,存入内存中,再次需要下载图片时,先去内存中查询,如果已经下载过,那么直接获取,如果没有获取过,再去下载。
存:
注意:
一直存会容易c内存溢出OOM
HashMap < String,Bitmap > cache ;
cache.put(“images/jsjs.jpg”,bitmap);
cache.put(“images/jsjs.jpg”,bitmap);
cache.put(“images/jsjs.jpg”,bitmap);
cache.put(“images/jsjs.jpg”,bitmap);
cache.put(“images/jsjs.jpg”,bitmap);
WeakHashMap:
弱引用,当java的内存达到阈值的时候,会随机删除键值对。
取:
Bitmap bitmap=cache.get(“images/jsjs.jpg”);
改进后:
HashMap < String,SoftReference> map;
map.put(path,new SoftReference(bitmap));
map.get(path).get();
代码参考上方例子
图片的文件缓存
(1)下载图片后,把图片数据保存到应用的缓存目录中。
public void save(File targetFile,Bitmap bitmap)//工具类存的方法
Bitmap bitmap;
FileOutputStream fos;//写出到文件
file.write();
//缓存目录都存到cach文件中
bimap.compress();//压缩方法
(2)再次获取图片时,先去内存缓存中去查询,如果没有则去缓存目录中查询。有则直接读取。没有的话再次发送请求。
public Bitmap loadBitmap(path)//工具类方法:通过路径加载bitmap,也可以出入压缩的比例
String path;
BitmapFactory.decodeFile(path,Options);
文件缓存工具类方法:
package com.tarena.musicclient.util;
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 {
/**
* 通过一个文件路径 查找到Bitmap
* @param path
* @return
* @throws IOException
*/
public static Bitmap loadBitmap(String path)throws IOException{
File file=new File(path);
if(file.exists()){
return BitmapFactory.decodeFile(path);
}
return null;
}
/***
* 保存图片
* @param targetFile 目标文件
* @param bitmap 位图对象
* @throws IOException
*/
public static void save(File targetFile, Bitmap bitmap)throws IOException{
if(!targetFile.getParentFile().exists()){
//父目录不存在 则创建
targetFile.getParentFile().mkdirs();
}
if(!targetFile.exists()){
targetFile.createNewFile();
}
//写入
FileOutputStream fos=new FileOutputStream(targetFile);
bitmap.compress(CompressFormat.JPEG, 100, fos);
}
/**
* 通过字节数组解析出Bitmap对象
* 需要按照一定的宽高的规格进行压缩
* @param bytes 数据源
* @param width 图片的目标宽度
* @param height 图片的目标高度
* @return
*/
public static Bitmap loadBitmap(byte[] bytes, int width, int height) {
Options opt=new Options();
//设置是否仅仅加载边界属性
opt.inJustDecodeBounds=true;
BitmapFactory.decodeByteArray(bytes, 0, bytes.length, opt);
//获取图片的原始的高度与宽度
int w=opt.outWidth/width;
int h=opt.outHeight/height;
int scale=w>h ? w : h;
//设置压缩比例
opt.inSampleSize=scale;
//再次进行解析Bitmap
opt.inJustDecodeBounds=false;
return BitmapFactory.decodeByteArray(bytes, 0, bytes.length, opt);
}
}
使用:
package com.tarena.musicclient.adapter;
import java.io.File;
import java.io.IOException;
import java.lang.ref.SoftReference;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import org.apache.http.HttpEntity;
import org.apache.http.util.EntityUtils;
import com.tarena.musicclient.activity.R;
import com.tarena.musicclient.entity.Music;
import com.tarena.musicclient.util.BitmapUtils;
import com.tarena.musicclient.util.GlobalConsts;
import com.tarena.musicclient.util.HttpUtils;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
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 Context context;
private List<Music> musics;
private LayoutInflater inflater;
//声明任务集合
private List<ImageLoadTask> tasks=new ArrayList<ImageLoadTask>();
private ListView listView;
//声明用于轮循任务集合的工作线程
private Thread workThread;
//声明变量控制while循环
private boolean isLoop=true;
//声明缓存集合
private HashMap<String, SoftReference<Bitmap>> cache
=new HashMap<String, SoftReference<Bitmap>>();
//声明Handler 更新ImageView
private Handler handler=new Handler(){
public void handleMessage(android.os.Message msg) {
switch (msg.what) {
case HANDLER_LOAD_IMAGE_SUCCESS:
//给ImageView设置Bitmap
ImageLoadTask task=(ImageLoadTask)msg.obj;
//通过tag寻找到相应的ImageView
ImageView ivAlum=(ImageView)listView.findViewWithTag(task.position);
if(ivAlum!=null){
if(task.bitmap!=null){
ivAlum.setImageBitmap(task.bitmap);
}else{
ivAlum.setImageResource(R.drawable.ic_launcher);
}
}
break;
}
}
};
public static final int HANDLER_LOAD_IMAGE_SUCCESS=0;
public MusicAdapter(Context context, List<Music> musics, ListView listView) {
this.context=context;
this.musics=musics;
this.listView=listView;
inflater=LayoutInflater.from(context);
//对workThread进行初始化
workThread=new Thread(){
public void run() {
//不断轮循任务集合
while(isLoop){
//如果任务集合不是空集
if(!tasks.isEmpty()){
//获取任务对象并且发送请求
ImageLoadTask task = tasks.remove(0);
Bitmap bitmap=loadBitmap(task.path);
task.bitmap=bitmap;
//给相应的ImageView设置Bitmap handler
Message msg=new Message();
msg.what=HANDLER_LOAD_IMAGE_SUCCESS;
msg.obj=task;
handler.sendMessage(msg);
}else{
synchronized (workThread) {
//如果任务集合是空集 wait等待
try {
workThread.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
};
workThread.start();
}
/**
* 通过path 获取Bitmap
* @param path
* @return
*/
public Bitmap loadBitmap(String path){
Bitmap bitmap=null;
String uri=GlobalConsts.BASEURL+path;
try {
HttpEntity entity=HttpUtils.send(HttpUtils.METHOD_GET, uri, null);
byte[] bytes=EntityUtils.toByteArray(entity);
bitmap=BitmapUtils.loadBitmap(bytes, 50, 50);
//向缓存集合中存储缓存图片
cache.put(path, new SoftReference<Bitmap>(bitmap));
//向文件缓存中存储图片
//cacheDir: /data/data/com.xxx.client/cache/
//path: images/xxxx.jpg
File targetFile=new File(context.getCacheDir(), path);
BitmapUtils.save(targetFile, bitmap);
} catch (IOException e) {
e.printStackTrace();
}
return bitmap;
}
@Override
public int getCount() {
return musics.size();
}
public Object getItem(int position) {
return musics.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder=null;
if(convertView==null){
convertView=inflater.inflate(R.layout.item_lv_music, null);
holder=new ViewHolder();
holder.ivAlbum=(ImageView)convertView.findViewById(R.id.imageView1);
holder.tvName=(TextView)convertView.findViewById(R.id.tvName);
holder.tvDuration=(TextView)convertView.findViewById(R.id.tvDuration);
holder.tvSinger=(TextView)convertView.findViewById(R.id.tvSinger);
holder.tvAuthor=(TextView)convertView.findViewById(R.id.tvAuthor);
convertView.setTag(holder);
}
holder=(ViewHolder)convertView.getTag();
//给控件赋值
Music music=musics.get(position);
holder.tvName.setText(music.getName());
holder.tvSinger.setText(music.getSinger());
holder.tvAuthor.setText(music.getAuthor());
holder.tvDuration.setText(music.getDurationtime());
//给当前item中的ImageView设置一个Tag
//用于图片下载完成后根据该tag
//找到相应的ImageView
holder.ivAlbum.setTag(position);
Bitmap bitmap=getCacheBitmap(music.getAlbumpic());
if(bitmap!=null){
holder.ivAlbum.setImageBitmap(bitmap);
return convertView;
}
//下载一张图片
//向任务队列中添加一个图片任务
ImageLoadTask task=new ImageLoadTask();
//albumPic: images/xxxxx.jpg
task.path=music.getAlbumpic();
task.position=position;
tasks.add(task);
//唤醒工作线程 起来干活
notifyWorkThread();
return convertView;
}
private Bitmap getCacheBitmap(String path){
//查询缓存中是否有图片 如果有 则直接获取
SoftReference<Bitmap> ref=cache.get(path);
if(ref!=null && ref.get()!=null){
Bitmap bitmap=ref.get();
System.out.println("从缓存中读取图片..");
return bitmap;
}
//查询文件缓存
File targetFile=new File(context.getCacheDir(), path);
Bitmap bitmap;
try {
bitmap = BitmapUtils.loadBitmap(targetFile.getAbsolutePath());
//如果文件中查到了bitmap
//那么存入内存缓存
if(bitmap!=null){
System.out.println("从文件缓存中读取图片..");
cache.put(path, new SoftReference<Bitmap>(bitmap));
}
return bitmap;
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
/**
* 唤醒工作线程
*/
public void notifyWorkThread(){
synchronized (workThread) {
workThread.notify();
}
}
class ImageLoadTask{
String path;
Bitmap bitmap;
int position;
}
class ViewHolder{
ImageView ivAlbum;
TextView tvName;
TextView tvDuration;
TextView tvSinger;
TextView tvAuthor;
}
public void stopWorkThread() {
isLoop=false;
notifyWorkThread();
}
}