简单图片加载框架的打造(三)-加载器缓存器设计

Posted by 夏敏的博客 on July 17, 2017

上一章解分发器的设计:简单图片加载框架的打造(二)-分发器设计RequestQueue

加载器与缓存器的接口都在第一章定好了,这边只需要完成其接口.我们看一下UML图

Loader

Loader我们实现一个实现ILoader的BaseLoader类,这边用到了策略模式,其下有加载本地图片的Loader,加载网络请求的Loader.

BaseLoader类中,需要先去缓存中获取Bitmap,获取到了直接设置,获取不到,就去调用子类的加载方法去加载.

public abstract class BaseLoader implements ILoader {

    public static BitmapCache mBitmapCache = SherlockImageLoader.getInstance()
            .getImageLoaderConfig()
            .getmBitmapCache();
    public static Handler handler = new Handler(Looper.getMainLooper());

    @Override
    public void loadImage(BitmapRequest request) {
        /** 从缓存中取bitmap */
        Bitmap bitmap = mBitmapCache.get(request);

        if (bitmap == null) {
            L.i("获取缓存失败,先显示Loading图");
            showLoadingImage(request);

            bitmap = onLoad(request);

            cacheBitmap(request, bitmap);
        }

        deliveryToUIThread(request, bitmap);
    }

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

    protected abstract Bitmap onLoad(BitmapRequest request);

    /**
     * 显示加载中图片
     * @param request
     */
    private void showLoadingImage(final BitmapRequest request) {
        if (request.getDisplayConfig() != null) {
            final ImageView imageview = request.getImageView();
            if (imageview == null) {
                return;
            }
            handler.post(new Runnable() {
                @Override
                public void run() {
                    imageview.setImageResource(request.getDisplayConfig().loadingImage);
                }
            });
        }
    }


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

    }

    private void updateImageView(final BitmapRequest request, final Bitmap bitmap) {
        ImageView imageView = request.getImageView();
        L.d("更新UI");
        if (imageView == null) {
            L.d("为空.返回");
            return;
        }

        //加载正常  防止图片错位
        if (bitmap != null && imageView.getTag().equals(request.getImageURL())) {
            L.d("加载正常");
            imageView.setImageBitmap(bitmap);
        } else {
            L.d("加载失败,TAG不对");
        }
        //有可能加载失败
        if (bitmap == null
                && request.getDisplayConfig() != null
                && request.getDisplayConfig().failedImage != -1) {
            L.d("加载失败,显示默认");
            imageView.setImageResource(request.getDisplayConfig().failedImage);
        }
        //监听
        //回调 给圆角图片  特殊图片进行扩展
        if (request.getCallback() != null) {
            request.getCallback().onSuccess(bitmap, request.getImageURL());
        }
    }
}

缓存策略

缓存直接写了几个实现BitmapCache接口的类就行了.

  • RAMCache内存缓存 使用 LruCache<String, Bitmap> mLruCache;
  • RomCache磁盘缓存 使用 DiskLruCache
  • DoubleCache 即先从内存取,取不到从磁盘取.

举个列子RAM缓存代码

public class RAMCache implements BitmapCache {

    private LruCache<String, Bitmap> mLruCache;

    public RAMCache() {
        int maxSize = (int) (Runtime.getRuntime().maxMemory() / 4);
        L.d("RAMCache maxSize: " + maxSize);
        mLruCache = new LruCache<String, Bitmap>(maxSize) {
            @Override
            protected int sizeOf(String key, Bitmap value) {
                int size = value.getRowBytes() * value.getHeight();
                L.d("size = " + size);
                return size;
            }
        };
    }

    @Override
    public void put(BitmapRequest bitmapRequest, Bitmap bitmap) {
        mLruCache.put(bitmapRequest.getImageUriMD5(), bitmap);
    }

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

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

调试

好了,到这步图片加载框架基本上完成了,配置的就没写了,具体在代码中看吧,框架还有很多要完善的,不过锻炼一下架构思维是关键.

工程路径,里面还有我准备写的数据库lib,还有httplib,只看ImageLoaderlib即可. https://github.com/Jerey-Jobs/Sherlock


本文作者:Anderson/Jerey_Jobs

博客地址 : http://jerey.cn/
简书地址 : Anderson大码渣
github地址 : https://github.com/Jerey-Jobs

作者:Anderson大码渣,欢迎关注我的简书: Anderson大码渣