ImageLoader的原理

来源:互联网 发布:去工业化知乎 编辑:程序博客网 时间:2024/04/30 04:23
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;    }}
0 0