ImageLoader的原理
16lz
2021-01-26
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 LruCachelru = new LruCache(max_Mamory){ protected int sizeOf(String key, Bitmap value) { //返回添加图片的大小 return value.getByteCount(); }; };//内存中存放网络下载图片容器 //存储ImageView放置imageview对象覆盖 ListimgList = new ArrayList(); 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; }}
更多相关文章
- Android手指绘图(一)
- android 图片拖动简单例子
- pagertab 自定义控件碎片滑动
- Android(安卓)RecyclerView实现viewpager效果
- viewpager+fragment+radiogroup横向滑动切换界面
- 如何使用Android(安卓)MediaStore裁剪大图片
- 读取网路图片
- 8 Android(安卓)gallery
- android多线程Handler