Xutil之BitmapUtil异步加载图片代码赏析

最近一直在研究Xutil代码的解析,发现代码写的不错,无论是从代码的质量上还是设计上堪称经典,所以写一下它的解析,看一下它的设计理念,对咱们日常的开发起到很大的作用。
Xutil系列分为几个系列,先写第一个BitmapUtil的解析,它是异步加载图片,采用线程池下载,图片显示和缓存一些列的功能集合。
1:使用:

bit = new BitmapUtils(activity);
bit.display(holder.imageView, list.get(position).getPic(), new DefaultBitmapLoadCallBack() {
@Override
public void onLoadCompleted(ImageView container, String uri, Bitmap bitmap, BitmapDisplayConfig config, BitmapLoadFrom from) {
super.onLoadCompleted(container, uri, zoomBitmap(bitmap, (int) (180 * b), (int) (100 * b)), config, from);

    holder.imageView.setImageBitmap(zoomBitmap(bitmap, (int) (180 * b), (int) (100 * b)));

}

@Override
public void onLoadFailed(ImageView container, String uri, Drawable drawable) {
    super.onLoadFailed(container, uri, drawable);
    Bitmap bitmap = BitmapFactory.decodeResource(activity.getResources(), R.drawable.default10);
    container.setImageBitmap(zoomBitmap(bitmap, (int) (180 * b), (int) (100 * b)));
}

});

使用起来非常简单,传递控件,url地址,图片加载成功和失败的回调。当然你也可以不写图片加载之后的回调。
2:我们具体研究的是代码设计。

看这个实际上看不出来啥大笑,主要是能明白这个类主要的功能逻辑和代码结构。上面的调用其实很简单,走一遍他的加载流程。

public interface TaskHandler {
boolean supportPause();

boolean supportResume();

boolean supportCancel();

void pause();

void resume();

void cancel();

boolean isPaused();

boolean isCancelled();

}
这个父接口,起到控制作用,对整个加载图片的流程进行了控制和梳理。
public class BitmapUtils implements TaskHandler {
private boolean pauseTask;
private boolean cancelAllTask;
private final Object pauseTaskLock;
private Context context;
private BitmapGlobalConfig globalConfig;
private BitmapDisplayConfig defaultDisplayConfig;
代码里面有任务锁,因为是多任务,在Adapter中的getview时,可能一下子要加载20多张图片。那么它是如何实现多线程下载的呢?偷笑

public BitmapUtils(Context context, String diskCachePath, int memoryCacheSize, int diskCacheSize) {
this(context, diskCachePath);
this.globalConfig.setMemoryCacheSize(memoryCacheSize);
this.globalConfig.setDiskCacheSize(diskCacheSize);
}
先看一下他的构造函数,里面涉及到文件缓存,内存缓存,可以看出,
globalConfig是他的配置属性。关于配置的一些属性交给他来进行处理、
BitmapDisplayConfig 是负责展示图片。
后续这两块我们还会进行详解。

public void display(T container, String uri, BitmapDisplayConfig displayConfig, BitmapLoadCallBack callBack) {
if(container != null) {
if(callBack == null) { // 图片加载之后的回调
callBack = new DefaultBitmapLoadCallBack();
}

    if(displayConfig == null || displayConfig == this.defaultDisplayConfig) {
    // 显示配置,稍后我们会详细介绍这块。
        displayConfig = this.defaultDisplayConfig.cloneNew();
    }

    BitmapSize size = displayConfig.getBitmapMaxSize();
    displayConfig.setBitmapMaxSize(BitmapCommonUtils.optimizeMaxSizeByView(container, size.getWidth(), size.getHeight()));
    container.clearAnimation();
    if(TextUtils.isEmpty(uri)) {
        ((BitmapLoadCallBack)callBack).onLoadFailed(container, uri, displayConfig.getLoadFailedDrawable());
    } else {// 注意加载逻辑,是先从内存缓存中取
        ((BitmapLoadCallBack)callBack).onPreLoad(container, uri, displayConfig);
        Bitmap bitmap = this.globalConfig.getBitmapCache().getBitmapFromMemCache(uri, displayConfig);
        if(bitmap != null) {
            ((BitmapLoadCallBack)callBack).onLoadStarted(container, uri, displayConfig);
            ((BitmapLoadCallBack)callBack).onLoadCompleted(container, uri, bitmap, displayConfig, BitmapLoadFrom.MEMORY_CACHE);
        } else if(!bitmapLoadTaskExist(container, uri, (BitmapLoadCallBack)callBack)) {// 没有的情况下才联网获取,没有的话开启异步任务喽,后续我们会进一步的研究这个异步任务类
            BitmapUtils.BitmapLoadTask loadTask = new BitmapUtils.BitmapLoadTask(container, uri, displayConfig, (BitmapLoadCallBack)callBack);
            PriorityExecutor executor = this.globalConfig.getBitmapLoadExecutor();
            File diskCacheFile = this.getBitmapFileFromDiskCache(uri);
            boolean diskCacheExist = diskCacheFile != null && diskCacheFile.exists();
            if(diskCacheExist && executor.isBusy()) {
                executor = this.globalConfig.getDiskCacheExecutor();
            }
            Drawable loadingDrawable = displayConfig.getLoadingDrawable();
            ((BitmapLoadCallBack)callBack).setDrawable(container, new AsyncDrawable(loadingDrawable, loadTask));
            loadTask.setPriority(displayConfig.getPriority());
            loadTask.executeOnExecutor(executor, new Object[0]);
        }
    }
}

}
这块代码就是具体的展示,采用了JAVA泛型,有兴趣的可以多了解一下,主要是为了适配各种View,上面作了部分注解,看下面的代码,在一个不知道有多少下载图片的任务的下载阶段,我们如何来进行多任务的下载和内存优化,唯一的答案就是利用好线程池。
private static boolean bitmapLoadTaskExist(T container, String uri, BitmapLoadCallBack callBack) {
BitmapUtils.BitmapLoadTask oldLoadTask = getBitmapTaskFromContainer(container, callBack);
if(oldLoadTask != null) {
String oldUrl = oldLoadTask.uri;
if(!TextUtils.isEmpty(oldUrl) && oldUrl.equals(uri)) {
return true;
}
oldLoadTask.cancel(true);
}
return false;
}
判断有没有存在这个线程任务。
下面是完整的内部任务类
public class BitmapLoadTask extends PriorityAsyncTask

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值