import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import android.annotation.SuppressLint;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.media.Image;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.support.v4.util.LruCache;
import android.util.Log;
import android.widget.AbsListView;
import android.widget.AbsListView.OnScrollListener;
import android.widget.AdapterView;
import android.widget.ImageView;
import android.widget.ListView;
/**
* 图片异步加载工具类:图片下载;添加给imageview
* 线程池:限制并行线程数(允许一定数量的线程同时运行,其他线程处于等待阶段)
* 图片异步加载时获取图片原理:1>Lru查找内存是否有本张图片->直接使用->下载成功过并且没有被清理
* 2>查找本地存储设备是否有本张图片->有:图片下载成功并且被lru清理;无:图片没有下载
* 3>通过网络连接下载图片
* ListView标志锁:作用当listview快速滑动(抛动)时,
* 防止加载多余(ListView快速滑动时划过的Item)的本地或网络图片
* OnScrollListener->判断listView滑动状态
* */
public class LoaderImg implements OnScrollListener{
private int max_Size = 5;//线程池核心线程数->可以同时进行下载操作的线程
private ExecutorService thread_pool;//线程池->限制线程马路
//android.support.v4.util.LruCache->为了兼容低版本jar包
//LruCache原理当存放value大小达到初始化时设置限定大小时进行清理内存操作
int max_Mamory = (int) Runtime.getRuntime().maxMemory()/10;//应用程序程序运行时所使用最大内存数
//每添加一条数据,返回添加数据的占用内存大小
@SuppressLint("NewApi")
private LruCache<String,Bitmap>lru = new LruCache<String, Bitmap>(max_Mamory){
protected int sizeOf(String key, Bitmap value) {
//返回添加图片的大小
return value.getByteCount();
};
};//内存中存放网络下载图片容器
//存储ImageView放置imageview对象覆盖
List<ImageView>imgList = new ArrayList<ImageView>();
boolean imgFlag = true;//是否向imglist中添加imageview标识
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>滑动标志锁使用
private boolean FlingFlag = true;//滑动标识(标志锁)
private int firstPosion = 0;//第一条显示的索引
private int visiblePosion = 0;//当前界面显示的条数
private String urlPath;//图片前端地址
private int bitmapID;//默认显示图片id
private int flag;//默认标志
private AbsListView lv;//listview
//LoaderImg异步加载图片入口
/**
* name:图片名称;
* urlPath:图片前段地址
* img:要显示图片的控件
* bitmapID:默认图片id
* flag->getView是否滑动最后一条->imglist中添加
* lv->正在显示的listview
* */
public void Load(String name,String urlPath,
ImageView img,int bitmapID,int flag,AbsListView lv){
if(name == null)
return;
if(urlPath == null)
return;
if(img == null)
return;
this.urlPath = urlPath;
this.bitmapID = bitmapID;
this.flag = flag;
this.lv = lv;
//img设置Tag在handler中判断下载完成图片与img要显示图片是否一致
img.setTag(name);
if(imgFlag){
imgList.add(img);
}
if(flag == -1){
imgFlag = false;
}
//设置默认显示图片
img.setImageResource(bitmapID);
//设置当前显示的listview滑动监听
lv.setOnScrollListener(this);
//启用滑动标志锁->不加载图片
if(!FlingFlag)
return;
//1>Lru中查找
Bitmap bitmap;
bitmap = lru.get(name);
if(bitmap != null){
img.setImageBitmap(bitmap);
}else{
//2>Lru中没有本张图片->本地查找
//3>网络下载图片
if(thread_pool == null){
//初始化线程池并且设置核心线程数->线程池中添加线程不需要使用start方法
thread_pool = Executors.newFixedThreadPool(max_Size);
}
//线程加入线程池
thread_pool.execute(new LoadThread(name, urlPath));
}
}
//接收下载完成图片
Handler hand = new Handler(){
public void handleMessage(android.os.Message msg) {
super.handleMessage(msg);
if(msg.what == 200){
//服务器下载回来图片
Bitmap bitmap = (Bitmap) msg.obj;
String name = msg.getData().getString("Name");
if(name!=null&&bitmap!=null){
//添加到Lrucatch中(1级缓存中)
lru.put(name, bitmap);
//添加到本地存储中(2级缓存)
//图片添加给ImageView显示
//判断ImageView对应显示图片->Tag判断->规避:图片错位->原因:图片复用机制引起
//缓存到imgList中的Imageview获取
ImageView img = null;//list中获取要显示下载完成图片的imageview
for(int i = 0;i < imgList.size();i++){
String tag = (String) imgList.get(i).getTag();
if(name.equals(tag)){
img = imgList.get(i);
break;
}
}
if(img != null)
//网络获取图片添加给对应imageview
img.setImageBitmap(bitmap);
}
}
};
};
private class LoadThread implements Runnable{
private String name;//图片名称
private String urlPath;//图片地址
public LoadThread(String name,String urlPath){
this.name = name;
this.urlPath = urlPath;
}
@Override
public void run() {
try {
URL url = new URL(urlPath+name);
HttpURLConnection httpc = (HttpURLConnection) url.openConnection();
httpc.setConnectTimeout(60*1000);
httpc.setReadTimeout(60*1000);
httpc.setDoInput(true);
if(httpc.getResponseCode() == 200){
InputStream in = httpc.getInputStream();
Bitmap resultBitmap = BitmapFactory.decodeStream(in);
Message msg = hand.obtainMessage();
msg.what = 200;
msg.obj = resultBitmap;
Bundle bund = new Bundle();
bund.putString("Name", name);
msg.setData(bund);//封装图片名称
hand.sendMessage(msg);
}
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
//当listview停止滚动时刷新item中imageview方法
private void RefrashItem(){
//获取ImageView出来->二次调用load()
visiblePosion = visiblePosion+1;
Log.e("",""+visiblePosion);
if(imgList.size()<5)
visiblePosion = imgList.size();
for(int i = (imgList.size()-1);i>=(imgList.size()-visiblePosion);i--){
ImageView img = imgList.get((i));
Log.e("", "name:"+(String)img.getTag());
Load((String)img.getTag(),
urlPath, img,
bitmapID, flag, lv);
}
}
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
if(scrollState == OnScrollListener.SCROLL_STATE_IDLE){
//停止->加载图片->打开滑动标志锁
FlingFlag = true;
//刷新界面
RefrashItem();
}else if(scrollState == OnScrollListener.SCROLL_STATE_FLING){
//抛动时->不加载图片->FlingFlag= false;->添加滑动标志锁
FlingFlag = false;
}else{
//滑动时->打开滑动标志锁
FlingFlag = true;
}
}
@Override
public void onScroll(AbsListView view, int firstVisibleItem,
int visibleItemCount, int totalItemCount) {
firstPosion = firstVisibleItem;
visiblePosion = visibleItemCount;
}
}
ImageLoader的原理
最新推荐文章于 2022-12-18 11:38:52 发布