移动架构36_图片加载框架

Android移动架构汇总​​​​​​​
##一、框架设计需求

根据用户需求可以灵活配置(建造者模式)
支持高并发,图片加载的优先级
支持可以选择不同的加载策略,对加载策略进行扩展
二级缓存 加载图片时内存中已经加载了,则从内存中加载,不存在去外置卡中加载,外置还不存在则从网络下载
并对缓存策略可以扩展
支持从加载过程中显示默认加载图片
支持加载失败时 显示默认错误图片
图片显示自适应。从网络加载下来的图片经最佳比例压缩后显示
不能失真变形
支持请求转发,下载

用到的模式:
生产者 消费者模式
建造者模式
单例模式
模板方法模式
策略模式

用到的知识点
内存缓存 LruCache技术
硬盘缓存技术DiskLruCache技术
图片下载时请求转发

##二、架构图
这里写图片描述

这里写图片描述

这里写图片描述

##三 、代码

demo地址:https://gitee.com/YuBaoZi/FangImageLoaderTuPianJiaZaiKuangJia

###1缓存策略

####1)定义图片缓存接口

public interface BitmapCache {
    /**
     * 缓存bitmap
     * @param bitmap
     */
    void put(BitmapRequest request, Bitmap bitmap);

    /**
     * 通过请求取Bitmap
     * @param request
     * @return
     */
    Bitmap get(BitmapRequest request);

    /**
     * 移除缓存
     * @param request
     */
    void remove(BitmapRequest request);
}

####2)使用DiskLruCache定义硬盘缓存,这里DisLruCache直接拿来用,不做过多介绍

public class DiskCache implements  BitmapCache {
    private static DiskCache mDiskCache;
    //缓存路径
    private String mCacheDir = "Image";
    //MB
    private static final int MB = 1024 * 1024;
    //jackwharton的杰作
    private DiskLruCache mDiskLruCache;

    private DiskCache(Context context)
    {
        iniDiskCache(context);
    }
    public static DiskCache getInstance(Context context) {
        if(mDiskCache==null)
        {
            synchronized (DiskCache.class)
            {
                if(mDiskCache==null)
                {
                    mDiskCache=new DiskCache(context);
                }
            }
        }
        return mDiskCache;
    }
    private void iniDiskCache(Context context) {
        //得到缓存的目录 
        File directory=getDiskCache(mCacheDir,context);
        if(!directory.exists())
        {
            directory.mkdir();
        }
        try {
            //最后一个参数 指定缓存容量
            mDiskLruCache=DiskLruCache.open(directory,1,1,50*MB);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private File getDiskCache(String mCacheDir, Context context) {
        String cachePath;
        //默认缓存路径
        return new File(Environment.getExternalStorageDirectory(),mCacheDir);
    }

    @Override
    public void put(BitmapRequest request, Bitmap bitmap) {
        DiskLruCache.Editor edtor=null;
        OutputStream os=null;
        try {
            //路径必须是合法字符
            edtor=mDiskLruCache.edit(request.getImageUriMD5());
            os=edtor.newOutputStream(0);
            if(persistBitmap2Disk(bitmap,os))
            {
                edtor.commit();
            }else {
                edtor.abort();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private boolean persistBitmap2Disk(Bitmap bitmap, OutputStream os) {
        BufferedOutputStream bos=new BufferedOutputStream(os);

        bitmap.compress(Bitmap.CompressFormat.JPEG,100,bos);
        try {
            bos.flush();
        } catch (IOException e) {
            e.printStackTrace();

        }finally {
            IOUtil.closeQuietly(bos);
        }
        return true;

    }

    @Override
    public Bitmap get(BitmapRequest request) {
        try {
            DiskLruCache.Snapshot snapshot=mDiskLruCache.get(request.getImageUriMD5());
            if(snapshot!=null)
            {
                InputStream inputStream=snapshot.getInputStream(0);
                return BitmapFactory.decodeStream(inputStream);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    @Override
    public void remove(BitmapRequest request) {
        try {
            mDiskLruCache.remove(request.getImageUriMD5());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

####3)内存缓存

public class MemoryCache implements  BitmapCache {
    private LruCache<String,Bitmap> mLruCache;
    public MemoryCache()
    {
        int maxSize= (int) (Runtime.getRuntime().freeMemory()/1024/8);
        mLruCache=new LruCache<String,Bitmap>(maxSize)
        {
            @Override
            protected int sizeOf(String key, Bitmap value) {
                return value.getRowBytes()*value.getHeight();
            }
        };
    }
    @Override
    public void put(BitmapRequest request, Bitmap bitmap) {
        mLruCache.put(request.getImageUriMD5(),bitmap);
    }

    @Override
    public Bitmap get(BitmapRequest request) {
        return mLruCache.get(request.getImageUriMD5());
    }

    @Override
    public void remove(BitmapRequest request) {
         mLruCache.remove(request.getImageUriMD5());
    }
}

####4)双缓存

public class DoubleCache implements BitmapCache {

    //内存缓存
    private MemoryCache mMemoryCache = new MemoryCache();
    //硬盘缓存
    private DiskCache mDiskCache;

    public DoubleCache(Context context) {
        mDiskCache = DiskCache.getInstance(context);
    }

    @Override
    public void put(BitmapRequest request, Bitmap bitmap) {
        mMemoryCache.put(request, bitmap);
        mDiskCache.put(request, bitmap);
    }

    @Override
    public Bitmap get(BitmapRequest request) {
        Bitmap bitmap = mMemoryCache.get(request);
        if(bitmap == null){
            bitmap = mDiskCache.get(request);
            if(bitmap != null){
                //放入内存,方便再获取
                mMemoryCache.put(request, bitmap);
            }
        }
        return bitmap;
    }

    @Override
    public void remove(BitmapRequest request) {
        mMemoryCache.remove(request);
        mDiskCache.remove(request);
    }

}

###2 加载策略

public interface LoadPolicy {
    /**
     * 两个BItmapRequest进行优先级比较
     * @param request1
     * @param request2
     * @return
     */
    int compareto(BitmapRequest request1,BitmapRequest request2);
}
public class ReversePolicy implements  LoadPolicy {
    @Override
    public int compareto(BitmapRequest request1, BitmapRequest request2) {
        return request2.getSerialNo()-request1.getSerialNo();
    }
}
public class SerialPolicy implements  LoadPolicy {
    @Override
    public int compareto(BitmapRequest request1, BitmapRequest request2) {
        return request1.getSerialNo()-request2.getSerialNo();
    }
}

###3 加载配置

public class DisplayConfig {
    /**
     * 加载过程中默认显示的图片Id
     */
    public int loadingImage=-1;
    //加载失败显示的图片
    public int faildImage=-1;
}
public class ImageLoaderConfig {
    //缓存策略
    private BitmapCache bitmapCache= new MemoryCache();
    //加载策略
    private LoadPolicy loadPolicy=new ReversePolicy();
    //默认线程数
    private int threadCount=Runtime.getRuntime().availableProcessors();
    //显示的配置
    private DisplayConfig displayConfig=new DisplayConfig();
    private  ImageLoaderConfig()
    {
    }
    /**
     * 建造者模式
     * 和AlterDialog建造过程类似
     */
    public static  class Builder
    {
        private ImageLoaderConfig config;
        public Builder()
        {
            config=new ImageLoaderConfig();
        }

        /**
         * 设置缓存策略
         * @param bitmapCache
         * @return
         */
        public Builder setCachePolicy(BitmapCache bitmapCache)
        {
            config.bitmapCache=bitmapCache;
            return this;
        }

        /**&
         * 设置加载策略
         * @param loadPolicy
         * @return
         */
        public Builder setLoadPolicy(LoadPolicy loadPolicy)
        {
            config.loadPolicy=loadPolicy;
            return this;
        }

        /**
         * 设置线程个数
         * @param count
         * @return
         */
        public Builder setThreadCount(int count)
        {
            config.threadCount=count;
            return this;
        }

        /**
         * 设置加载过程中的图片
         * @param resID
         * @return
         */
        public Builder setLoadingImage(int resID)
        {
            config.displayConfig.loadingImage=resID;
            return this;
        }
        /**
         * 设置加载过程中的图片
         * @param resID
         * @return
         */
        public Builder setFaildImage(int resID)
        {
            config.displayConfig.faildImage=resID;
            return this;
        }
        public ImageLoaderConfig build()
        {
            return  config;
        }
    }

    public BitmapCache getBitmapCache() {
        return bitmapCache;
    }

    public LoadPolicy getLoadPolicy() {
        return loadPolicy;
    }

    public int getThreadCount() {
        return threadCount;
    }

    public DisplayConfig getDisplayConfig() {
        return displayConfig;
    }
}

###4 定义具体加载器,实现图片加载

public interface Loader {
    /**
     * 加载图片
     * @param request
     */
    void loadImage(BitmapRequest request);
public abstract  class AbstarctLoader implements  Loader {
    //拿到用户自定义配置的缓存策略
    private BitmapCache bitmapCache=SimpleImageLoader.getInstance().getConfig().getBitmapCache();
    //拿到显示配置
    private DisplayConfig displayConfig=SimpleImageLoader.getInstance().getConfig().getDisplayConfig();


    @Override
    public void loadImage(BitmapRequest request) {
        //从缓存取到Bitmap
        Bitmap bitmap=bitmapCache.get(request);
        if(bitmap==null)
        {
            //显示默认加载图片
            showLoadingImage(request);
            //开始真正加载图片
            bitmap=onLoad(request);
            //缓存图片
            cacheBitmap(request,bitmap);
        }
        deliveryToUIThread(request,bitmap);
    }

    /**
     * 交给主线程显示
     * @param request
     * @param bitmap
     */
    protected void deliveryToUIThread(final BitmapRequest request, final Bitmap bitmap) {
        ImageView imageView = request.getImageView();
        if(imageView!=null)
        {
            imageView.post(new Runnable() {
                @Override
                public void run() {
                    updateImageView(request, bitmap);
                }

            });
        }

    }
    private void updateImageView(final BitmapRequest request, final Bitmap bitmap) {
        ImageView imageView = request.getImageView();
        //加载正常  防止图片错位
        if(bitmap != null && imageView.getTag().equals(request.getImageUrl())){
            imageView.setImageBitmap(bitmap);
        }
        //有可能加载失败
        if(bitmap == null && displayConfig!=null&&displayConfig.faildImage!=-1){
            imageView.setImageResource(displayConfig.faildImage);
        }
        //监听
        //回调 给圆角图片  特殊图片进行扩展
        if(request.imageListener != null){
            request.imageListener.onComplete(imageView, bitmap, request.getImageUrl());
        }
    }

    /**
     * 缓存图片
     * @param request
     * @param bitmap
     */
    private void cacheBitmap(BitmapRequest request, Bitmap bitmap) {
        if(request!=null&&bitmap!=null)
        {
            synchronized (AbstarctLoader.class)
            {
                bitmapCache.put(request,bitmap);
            }
        }
    }

    //抽象加载策略  因为加载网络图片和本地图片有差异
    protected abstract Bitmap onLoad(BitmapRequest request);


    /**
     * 加载前显示的图片
     * @param request
     */
    protected void showLoadingImage(BitmapRequest request) {
        //指定了,显示配置
        if(hasLoadingPlaceHolder()){
            final ImageView imageView = request.getImageView();
            if(imageView!=null)
            {
                imageView.post(new Runnable() {
                    @Override
                    public void run() {
                        imageView.setImageResource(displayConfig.loadingImage);
                    }
                });
            }

        }
    }

    protected boolean hasLoadingPlaceHolder(){
        return (displayConfig != null && displayConfig.loadingImage > 0);
    }

}
public class NullLoader extends  AbstarctLoader {
    @Override
    protected Bitmap onLoad(BitmapRequest request) {
        return null;
    }
}
public class UrlLoader extends  AbstarctLoader {
    @Override
    protected Bitmap onLoad(final BitmapRequest request) {
        //先下载  后读取
        downloadImgByUrl(request.getImageUrl(),getCache(request.getImageUriMD5()));
        BitmapDecoder decoder=new BitmapDecoder() {
            @Override
            public Bitmap decodeBitmapWithOption(BitmapFactory.Options options) {
                return BitmapFactory.decodeFile(getCache(request.getImageUriMD5()).getAbsolutePath(),options);
            }
        };
        return decoder.decodeBitmap(ImageViewHelper.getImageViewWidth(request.getImageView())
                    ,ImageViewHelper.getImageViewHeight(request.getImageView()));
    }

    public static boolean downloadImgByUrl(String urlStr, File file)
    {
        FileOutputStream fos = null;
        InputStream is = null;
        try
        {
            URL url = new URL(urlStr);
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();

            is = conn.getInputStream();
            fos = new FileOutputStream(file);
            byte[] buf = new byte[512];
            int len = 0;
            while ((len = is.read(buf)) != -1)
            {
                fos.write(buf, 0, len);
            }
            fos.flush();
            return true;

        } catch (Exception e)
        {
            e.printStackTrace();
        } finally
        {
            try
            {
                if (is != null)
                    is.close();
            } catch (IOException e)
            {
            }

            try
            {
                if (fos != null)
                    fos.close();
            } catch (IOException e)
            {
            }
        }

        return false;

    }
    private File getCache(String unipue)
    {
        File file=new File(Environment.getExternalStorageDirectory(),"ImageLoader");
        if(!file.exists())
        {
            file.mkdir();
        }
        return new File(file,unipue);
    }

}
public class LocalLoader extends  AbstarctLoader {
    @Override
    protected Bitmap onLoad(BitmapRequest request) {
        //得到本地图片的路径
        final String path= Uri.parse(request.getImageUrl()).getPath();
        File file=new File(path);
        if(!file.exists())
        {
            return null;
        }
        BitmapDecoder decoder=new BitmapDecoder() {
            @Override
            public Bitmap decodeBitmapWithOption(BitmapFactory.Options options) {
                return BitmapFactory.decodeFile(path,options);
            }
        };

        return decoder.decodeBitmap(ImageViewHelper.getImageViewWidth(request.getImageView())
                ,ImageViewHelper.getImageViewHeight(request.getImageView()));
    }
}
public class LoaderManager {
    //缓存所有支持的Loader类型
    private Map<String ,Loader> mLoaderMap=new HashMap<>();

    private  static  LoaderManager mInstance=new LoaderManager();
    private LoaderManager()
    {
        register("http",new UrlLoader());
        register("https",new UrlLoader());
        register("file",new  LocalLoader());
    }

    public static  LoaderManager getInstance()
    {
        return mInstance;
    }
    private void register(String schema,  Loader loader) {
        mLoaderMap.put(schema,loader);
    }

    public Loader getLoader(String schema)
    {
        if(mLoaderMap.containsKey(schema))
        {
            return mLoaderMap.get(schema);
        }
        return new NullLoader();
    }
}

###4 网络请求

public class BitmapRequest  implements Comparable<BitmapRequest> {
    //持有imageview的软引用
    private SoftReference<ImageView> imageViewSoft;
    //图片路径
    private String imageUrl;
    //MD5的图片路径
    private String imageUriMD5;
     //下载完成监听
    public SimpleImageLoader.ImageListener imageListener;

    private  DisplayConfig displayConfig;
    public BitmapRequest(ImageView imageView,String imageUrl,DisplayConfig displayConfig,
                         SimpleImageLoader.ImageListener imageListener) {
        this.imageViewSoft=new SoftReference<ImageView>(imageView);
        //设置可见的Image的Tag,要下载的图片路径
        imageView.setTag(imageUrl);
        this.imageUrl=imageUrl;
        this.imageUriMD5= MD5Utils.toMD5(imageUrl);
        if(displayConfig!=null)
        {
            this.displayConfig=displayConfig;
        }
        this.imageListener = imageListener;
    }

    //加载策略
    private LoadPolicy loadPolicy= SimpleImageLoader.getInstance().getConfig().getLoadPolicy();
    /**
     * 编号
     */
    private int serialNo;


    public int getSerialNo() {
        return serialNo;
    }

    public void setSerialNo(int serialNo) {
        this.serialNo = serialNo;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        BitmapRequest that = (BitmapRequest) o;

        if (serialNo != that.serialNo) return false;
        return loadPolicy != null ? loadPolicy.equals(that.loadPolicy) : that.loadPolicy == null;

    }

    @Override
    public int hashCode() {
        int result = loadPolicy != null ? loadPolicy.hashCode() : 0;
        result = 31 * result + serialNo;
        return result;
    }
    public ImageView getImageView()
    {
        return  imageViewSoft.get();
    }

    public String getImageUrl() {
        return imageUrl;
    }

    public String getImageUriMD5() {
        return imageUriMD5;
    }

    public DisplayConfig getDisplayConfig() {
        return displayConfig;
    }

    public LoadPolicy getLoadPolicy() {
        return loadPolicy;
    }

    @Override
    public int compareTo(BitmapRequest o) {
        return loadPolicy.compareto(o,this);
    }
}
/**
 * 转发器
 * 请求转发线程  不断从请求队列中获取请求
 */

public class RequestDispatcher extends  Thread{
    //请求队列
    private BlockingQueue<BitmapRequest> mRequestQueue;

    public RequestDispatcher(BlockingQueue<BitmapRequest> mRequestQueue) {
        this.mRequestQueue = mRequestQueue;
    }

    @Override
    public void run() {
        while (!isInterrupted())
        {
            try {
                //阻塞式函数
                BitmapRequest request=mRequestQueue.take();
                /**
                 * 处理请求对象
                 */
                String schema=parseSchema(request.getImageUrl());
                //获取加载器
                Loader loader= LoaderManager.getInstance().getLoader(schema);
                loader.loadImage(request);

            } catch (InterruptedException e) {
                e.printStackTrace();
            }


        }

    }

    private String parseSchema(String imageUrl) {
         if(imageUrl.contains("://"))
         {
             return imageUrl.split("://")[0];
         }
         else
         {
             Log.i(TAG,"不支持此类型");
         }

        return null;
    }
}
public class RequestQueue {
    /**
     *阻塞式队列
     * 多线程共享
     * 生产效率 和消费效率想查太远了。
     * disPlayImage()
     * 使用优先级队列
     * 优先级高的队列先被消费
     * 每 一个产品都有编号
     */
    private BlockingQueue<BitmapRequest> mRequestQueue=new PriorityBlockingQueue<>();
    /**
     * 转发器的数量
     */
    private int  threadCount;
    //i++  ++i  能 1   不能 2
    private AtomicInteger i=new AtomicInteger(0);
    //一组转发器
    private RequestDispatcher[] mDispachers;

    public RequestQueue(int threadCount) {
        this.threadCount = threadCount;
    }

    /**
     * 添加请求对象
     * @param request
     */
    public void addRequest(BitmapRequest request)
    {
        //判断请求队列是否包含请求
        if(!mRequestQueue.contains(request))
        {
            //给请求进行编号
            request.setSerialNo(i.incrementAndGet());
            mRequestQueue.add(request);
        }else
        {
            Log.i(TAG,"请求已经存在 编号:"+request.getSerialNo());
        }
    }

    /**
     * 开启请求
     */
    public void start()
    {
        //先停止
        stop();
        startDispatchers();

    }

    /**
     * 开启转发器
     */
    private void startDispatchers() {
        mDispachers=new RequestDispatcher[threadCount];
        for(int i=0;i<threadCount;i++)
        {
            RequestDispatcher p=new RequestDispatcher(mRequestQueue);
            mDispachers[i]=p;
            mDispachers[i].start();
        }
    }

    /**
     * 停止
     */
    public void stop()
    {

    }

}

###5 工具类

public abstract  class BitmapDecoder {
    public Bitmap decodeBitmap(int reqWidth,int reqHeight)
    {
        //初始化options
        BitmapFactory.Options options=new BitmapFactory.Options();
        //只需要读取图片宽高信息,无需将整张图片加载到内存 inJustDecodeBounds设置true
        options.inJustDecodeBounds=true;
        //根据options加载Bitmap  抽象
        decodeBitmapWithOption(options);
        //计算图片缩放比例
        calculateSampleSizeWithOption(options,reqWidth,reqHeight);

        return  decodeBitmapWithOption(options);
    }


    /**
     * 计算图片缩放的比例
     * @param options
     * @param reqWidth
     * @param reqHeight
     */
    private void calculateSampleSizeWithOption(BitmapFactory.Options options, int reqWidth, int reqHeight) {
        //计算缩放的比例
        //图片的原始宽高
        int width = options.outWidth;
        int height = options.outHeight;

        int inSampleSize = 1;
        //  reqWidth   ImageView的  宽
        if(width > reqWidth || height > reqHeight){
            //宽高的缩放比例
            int heightRatio = Math.round((float)height / (float)reqHeight);
            int widthRatio = Math.round((float)width / (float)reqWidth);

            //有的图是长图、有的是宽图
            inSampleSize = Math.max(heightRatio, widthRatio);
        }

        //全景图
        //当inSampleSize为2,图片的宽与高变成原来的1/2
        //options.inSampleSize = 2
        options.inSampleSize = inSampleSize;

        //每个像素2个字节
        options.inPreferredConfig = Bitmap.Config.RGB_565;
        //Bitmap占用内存  true
        options.inJustDecodeBounds = false;
        //当系统内存不足时可以回收Bitmap
        options.inPurgeable = true;
        options.inInputShareable = true;


    }

    public abstract  Bitmap  decodeBitmapWithOption(BitmapFactory.Options options);

}
public class ImageViewHelper {

    //默认的图片宽高
    private static int DEFAULT_WIDTH = 200;
    private static int DEFAULT_HEIGHT = 200;

    /**
     * 获取ImageView控件的宽度
     * 1.getWidth(绘制完成,如果视图没有绘制完成没有值)
     * 2.layout_width(有可能设置的是WRAP_CONTENT)
     * 3.maxWidth
     * 拿到ImageView的宽高
     * @param imageView
     * @return
     */
    public static int getImageViewWidth(ImageView imageView){
        if(imageView != null){
//          imageView.getWidth()==0;
            LayoutParams params = imageView.getLayoutParams();
            int width = 0;
            if(params != null && params.width != LayoutParams.WRAP_CONTENT){
                width = imageView.getWidth();
            }

            if(width <= 0 && params != null){
                width = params.width;
            }

            if(width <= 0){
                width = getImageViewFieldValue(imageView,"mMaxWidth");
            }
            return width;
        }

        return DEFAULT_WIDTH;
    }

    /**
     * 获取图片的高度
     * @param imageView
     * @return
     */
    public static int getImageViewHeight(ImageView imageView){
        if(imageView != null){
            LayoutParams params = imageView.getLayoutParams();
            int height = 0;
            if(params != null && params.height != LayoutParams.WRAP_CONTENT){
                height = imageView.getWidth();
            }
            if(height <= 0 && params != null){
                height = params.height;
            }
            if(height <= 0){
                height = getImageViewFieldValue(imageView,"mMaxHeight");
            }
            return height;
        }
        return DEFAULT_HEIGHT;
    }


    private static int getImageViewFieldValue(ImageView imageView,String fieldName) {
        try {
            Field field = ImageView.class.getDeclaredField(fieldName);
            field.setAccessible(true);
            int fieldValue = (Integer)field.get(imageView);
            if(fieldValue > 0 && fieldValue < Integer.MAX_VALUE){
                return fieldValue;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return 0;
    }

}
public class MD5Utils {

    private static MessageDigest digest;

    static{
        try {
            digest = MessageDigest.getInstance("MD5");
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
            Log.d("jason", "md5 算法不支持!");
        }
    }

    /**
     * MD5加密
     * @param key
     * @return
     */
    public static String toMD5(String key){
        if(digest == null){
            return String.valueOf(key.hashCode());
        }
        //更新字节
        digest.update(key.getBytes());
        //获取最终的摘要  十进制的  12345678/ABCD1245
        return convert2HexString(digest.digest());
    }

    /**
     * 转为16进制字符串
     * @param bytes
     * @return
     */
    private static String convert2HexString(byte[] bytes) {
        StringBuffer sb = new StringBuffer();
        for (byte b : bytes) {
            //->8->08
            String hex = Integer.toHexString(0xFF & b);
            if(hex.length() == 1){
                sb.append('0');
            }
            sb.append(hex);
        }
        return sb.toString();
    }

}
public class SimpleImageLoader {
    //配置
    private ImageLoaderConfig config;
    //请求队列
    private RequestQueue mRequestQueue;
    //单例对象
    private static volatile  SimpleImageLoader mInstance;
    private SimpleImageLoader()
    {

    }
    private SimpleImageLoader(ImageLoaderConfig imageLoaderConfig)
    {
        this.config=imageLoaderConfig;
        mRequestQueue=new RequestQueue(config.getThreadCount());
        //开启请求队列
        mRequestQueue.start();
    }

    /**
     * 获取单例方法
     * 第一次调用
     * @param config
     * @return
     */
    public  static SimpleImageLoader getInstance(ImageLoaderConfig config)
    {
        if(mInstance==null)
        {
            synchronized (SimpleImageLoader.class)
            {
                if(mInstance==null)
                {
                    mInstance=new SimpleImageLoader(config);
                }
            }

        }
        return  mInstance;
    }

    /**
     * 第二次获取单例
     * @return
     */
    public static SimpleImageLoader getInstance()
    {
        if(mInstance==null)
        {
            throw  new UnsupportedOperationException("没有初始化");
        }
        return mInstance;
    }

    /**
     *暴露获取图片
     * @param imageView
     * @param uri  http:   file 开头
     */
    public  void displayImage(ImageView imageView,String uri)
    {
        displayImage(imageView,uri,null,null);
    }

    /**
     * 重载
     * @param imageView
     * @param uri
     * @param displayConfig
     * @param imageListener
     */
    public  void displayImage(ImageView imageView, String uri
            , DisplayConfig displayConfig,ImageListener imageListener)
    {
        //实例化一个请求
        BitmapRequest bitmapRequest=new BitmapRequest(imageView,uri,displayConfig,imageListener);
        //添加到队列里面
        mRequestQueue.addRequest(bitmapRequest);
    }
    public static  interface ImageListener{
        /**
         *
         * @param imageView
         * @param bitmap
         * @param uri
         */
        void onComplete(ImageView imageView, Bitmap bitmap,String uri);
    }

    /**
     * 拿到全局配置
     * @return
     */
    public ImageLoaderConfig getConfig() {
        return config;
    }
}

###6 使用

public class MainActivity extends AppCompatActivity {
    SimpleImageLoader imageLoader;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.list);
        GridView listview = (GridView) findViewById(R.id.listview);
        listview.setAdapter(new MyAdapter(this));

        //配置
        ImageLoaderConfig.Builder build = new ImageLoaderConfig.Builder();
        build.setThreadCount(3) //线程数量
                .setLoadPolicy(new ReversePolicy()) //加载策略
                .setCachePolicy(new DoubleCache(this)) //缓存策略
                .setLoadingImage(R.drawable.loading)
                .setFaildImage(R.drawable.not_found);

        ImageLoaderConfig config = build.build();
        //初始化
        imageLoader = SimpleImageLoader.getInstance(config);

    }

    class MyAdapter extends BaseAdapter {

        private LayoutInflater inflater;

        public MyAdapter(Context context) {
            inflater = LayoutInflater.from(context);
        }

        @Override
        public int getCount() {
            return imageThumbUrls.length;
        }

        @Override
        public Object getItem(int position) {
            return imageThumbUrls[position];
        }

        @Override
        public long getItemId(int position) {
            return position;
        }

        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            View item = inflater.inflate(R.layout.item, null);
            ImageView imageView = (ImageView) item.findViewById(R.id.iv);
            //请求图片
            imageLoader.displayImage(imageView, imageThumbUrls[position]);
            return item;
        }

    }


    public final static String[] imageThumbUrls =new String[] {
            "https://img-my.csdn.net/uploads/201407/26/1406383299_1976.jpg",
            "https://img-my.csdn.net/uploads/201407/26/1406383291_6518.jpg",
            "https://img-my.csdn.net/uploads/201407/26/1406383291_8239.jpg",
            "https://img-my.csdn.net/uploads/201407/26/1406383290_9329.jpg",//DB123421AC
            "https://img-my.csdn.net/uploads/201407/26/1406383290_1042.jpg",
            "https://img-my.csdn.net/uploads/201407/26/1406383275_3977.jpg",
            "https://img-my.csdn.net/uploads/201407/26/1406383265_8550.jpg",
            "https://img-my.csdn.net/uploads/201407/26/1406383264_3954.jpg",
            "https://img-my.csdn.net/uploads/201407/26/1406383264_4787.jpg",
            "https://img-my.csdn.net/uploads/201407/26/1406383264_8243.jpg",
            "https://img-my.csdn.net/uploads/201407/26/1406383248_3693.jpg",
            "https://img-my.csdn.net/uploads/201407/26/1406383243_5120.jpg",
            "https://img-my.csdn.net/uploads/201407/26/1406383242_3127.jpg",
            "https://img-my.csdn.net/uploads/201407/26/1406383242_9576.jpg",
            "https://img-my.csdn.net/uploads/201407/26/1406383242_1721.jpg",
            "https://img-my.csdn.net/uploads/201407/26/1406383219_5806.jpg",
            "https://img-my.csdn.net/uploads/201407/26/1406383214_7794.jpg",
            "https://img-my.csdn.net/uploads/201407/26/1406383213_4418.jpg",
            "https://img-my.csdn.net/uploads/201407/26/1406383213_3557.jpg",
            "https://img-my.csdn.net/uploads/201407/26/1406383210_8779.jpg",
            "https://img-my.csdn.net/uploads/201407/26/1406383172_4577.jpg",
            "https://img-my.csdn.net/uploads/201407/26/1406383166_3407.jpg",
            "https://img-my.csdn.net/uploads/201407/26/1406383166_2224.jpg",
            "https://img-my.csdn.net/uploads/201407/26/1406383166_7301.jpg",
            "https://img-my.csdn.net/uploads/201407/26/1406383165_7197.jpg",
            "https://img-my.csdn.net/uploads/201407/26/1406383150_8410.jpg",
            "https://img-my.csdn.net/uploads/201407/26/1406383131_3736.jpg",
            "https://img-my.csdn.net/uploads/201407/26/1406383130_5094.jpg",
            "https://img-my.csdn.net/uploads/201407/26/1406383130_7393.jpg",
            "https://img-my.csdn.net/uploads/201407/26/1406383129_8813.jpg",
            "https://img-my.csdn.net/uploads/201407/26/1406383100_3554.jpg",
            "https://img-my.csdn.net/uploads/201407/26/1406383093_7894.jpg",
            "https://img-my.csdn.net/uploads/201407/26/1406383092_2432.jpg",
            "https://img-my.csdn.net/uploads/201407/26/1406383092_3071.jpg",
            "https://img-my.csdn.net/uploads/201407/26/1406383091_3119.jpg",
            "https://img-my.csdn.net/uploads/201407/26/1406383059_6589.jpg",
            "https://img-my.csdn.net/uploads/201407/26/1406383059_8814.jpg",
            "https://img-my.csdn.net/uploads/201407/26/1406383059_2237.jpg",
            "https://img-my.csdn.net/uploads/201407/26/1406383058_4330.jpg",
            "https://img-my.csdn.net/uploads/201407/26/1406383038_3602.jpg",
            "https://img-my.csdn.net/uploads/201407/26/1406382942_3079.jpg",
            "https://img-my.csdn.net/uploads/201407/26/1406382942_8125.jpg",
            "https://img-my.csdn.net/uploads/201407/26/1406382942_4881.jpg",
            "https://img-my.csdn.net/uploads/201407/26/1406382941_4559.jpg",
            "https://img-my.csdn.net/uploads/201407/26/1406382941_3845.jpg",
            "https://img-my.csdn.net/uploads/201407/26/1406382924_8955.jpg",
            "https://img-my.csdn.net/uploads/201407/26/1406382923_2141.jpg",
            "https://img-my.csdn.net/uploads/201407/26/1406382923_8437.jpg",
            "https://img-my.csdn.net/uploads/201407/26/1406382922_6166.jpg",
            "https://img-my.csdn.net/uploads/201407/26/1406382922_4843.jpg",
            "https://img-my.csdn.net/uploads/201407/26/1406382905_5804.jpg",
            "https://img-my.csdn.net/uploads/201407/26/1406382904_3362.jpg",
            "https://img-my.csdn.net/uploads/201407/26/1406382904_2312.jpg",
            "https://img-my.csdn.net/uploads/201407/26/1406382904_4960.jpg",
            "https://img-my.csdn.net/uploads/201407/26/1406382900_2418.jpg",
            "https://img-my.csdn.net/uploads/201407/26/1406382881_4490.jpg",
            "https://img-my.csdn.net/uploads/201407/26/1406382881_5935.jpg",
            "https://img-my.csdn.net/uploads/201407/26/1406382880_3865.jpg",
            "https://img-my.csdn.net/uploads/201407/26/1406382880_4662.jpg",
            "https://img-my.csdn.net/uploads/201407/26/1406382879_2553.jpg",
            "https://img-my.csdn.net/uploads/201407/26/1406382862_5375.jpg",
            "https://img-my.csdn.net/uploads/201407/26/1406382862_1748.jpg",
            "https://img-my.csdn.net/uploads/201407/26/1406382861_7618.jpg",
            "https://img-my.csdn.net/uploads/201407/26/1406382861_8606.jpg",
            "https://img-my.csdn.net/uploads/201407/26/1406382861_8949.jpg",
            "https://img-my.csdn.net/uploads/201407/26/1406382841_9821.jpg",
            "https://img-my.csdn.net/uploads/201407/26/1406382840_6603.jpg",
            "https://img-my.csdn.net/uploads/201407/26/1406382840_2405.jpg",
            "https://img-my.csdn.net/uploads/201407/26/1406382840_6354.jpg",
            "https://img-my.csdn.net/uploads/201407/26/1406382839_5779.jpg",
            "https://img-my.csdn.net/uploads/201407/26/1406382810_7578.jpg",
            "https://img-my.csdn.net/uploads/201407/26/1406382810_2436.jpg",
            "https://img-my.csdn.net/uploads/201407/26/1406382809_3883.jpg",
            "https://img-my.csdn.net/uploads/201407/26/1406382809_6269.jpg",
            "https://img-my.csdn.net/uploads/201407/26/1406382808_4179.jpg",
            "https://img-my.csdn.net/uploads/201407/26/1406382790_8326.jpg",
            "https://img-my.csdn.net/uploads/201407/26/1406382789_7174.jpg",
            "https://img-my.csdn.net/uploads/201407/26/1406382789_5170.jpg",
            "https://img-my.csdn.net/uploads/201407/26/1406382789_4118.jpg",
            "https://img-my.csdn.net/uploads/201407/26/1406382788_9532.jpg",
            "https://img-my.csdn.net/uploads/201407/26/1406382767_3184.jpg",
            "https://img-my.csdn.net/uploads/201407/26/1406382767_4772.jpg",
            "https://img-my.csdn.net/uploads/201407/26/1406382766_4924.jpg",
            "https://img-my.csdn.net/uploads/201407/26/1406382766_5762.jpg",
            "https://img-my.csdn.net/uploads/201407/26/1406382765_7341.jpg" };
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。
1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值