开源项目分析之UIL(续)

开源项目分析之UIL(续)_第1张图片
先直接上流程图
在上一篇我们大概的浏览了一下图片是怎样网络到本地,然后显示出来的。这一讲我们要分析一些细节问题。
图片的处理思路
该开源项目的处理也是符合真实世界的思路的,有几个问题我们需要理清楚
1.我们拥有什么 图片的url和ImageView
2.我们希望怎样处理图片 从网络上解析bitmap,缓存到磁盘,缓存到本地,显示出来
那么,我就分几个模块分析一下
下载图片
我们之前通过分析指导,下载图片是由一个Runnable来完成的,这是一个异步操作。

LoadAndDisplayImageTask displayTask = new LoadAndDisplayImageTask(engine, imageLoadingInfo, defineHandler(options));

我们通过ImageLoaderEngine来执行这个任务,他内部封装了一个Executor,实际是通过开启子线程来执行这个任务。那么最后的执行实体还是在run方法里面。那么既然我已经开启了一个加载任务,其实是因为之前我们在磁盘和内存缓存中并没有找到。那么我加载到后,就要先缓存在磁盘,内存,然后再开启一个显示图片的任务,当然,此时我们已经得到bitmap了。这里的ImageDownLoader是专门用于从网络去下载图片的,但是呢,他并不是将拿到的输入流直接解析为bitmap,而是将流保存在本地,如果用户选择了缓存到磁盘,那么他将该流缓存在磁盘,并对磁盘中的流进行解析,得到bitmap.这边还有一个解析器,是专门将bitmap流解析为bitmap的,如果你选择了缓存到磁盘,那么我们解析磁盘中的流,否则,直接解析uri,即网络流。反正最后我们得到的肯定是一个bitmap。请注意,这上面的一切都是在子线程中做的。仔细看下图,我们可以发现PreProcessor和PostProcess,前者是拿到bitmap后,缓存到内存之前所做的处理,后者是从缓存中拿出后,准备显示到ImageView上时需要做的处理。后面接着就是开启一个显示的任务。

DisplayBitmapTask displayBitmapTask = new DisplayBitmapTask(bmp, imageLoadingInfo, engine, loadedFrom);
        runTask(displayBitmapTask, syncLoading, handler, engine);

我们知道,显示图片必须在UI线程完成,那么,他是怎么保证的呢?我们可以看到有defineHandler这个方法

private static Handler defineHandler(DisplayImageOptions options) { Handler handler = options.getHandler();
        if (options.isSyncLoading()) {
            handler = null;
        } else if (handler == null && Looper.myLooper() == Looper.getMainLooper()) { handler = new Handler();
        }
        return handler;
    }

他必须确保Handler是和主轮询器绑定的,也就是在主线程中。
磁盘缓存
这里面他默认用的是LruDiskCache,那么我们就一起来看一看他是怎么缓存的,又是怎么取出的呢?
这其实是一个自己封装的类,其实质还是用的总所周知的DiskLruCache.毕竟为了实现一些特殊的需求,LruDiskCache需要更多的参数。

LruDiskCache(individualCacheDir,reserveCacheDir,diskCacheFileNameGenerator, diskCacheSize,diskCacheFileCount)

第一个参数 是我们要缓存的目录,第二个是备用的,第三个是名字产生器,就是根据uri来产生一个缓存的文件的名字。
1.怎么保存的呢?
save 好吧,必须要分析一下DiskLruCache的内部类Editor了。它里面有个成员变量written

private Editor(Entry entry) {
            this.entry = entry;
            this.written = (entry.readable) ? null : new boolean[valueCount];
        }

看看他是怎么初始化的,这个valueCount表示的是你的缓存文件要保存的数量。那么他又是怎么实现
一个key值对应多个缓存文件的呢? 他的文件的命名如下:

public File getDirtyFile(int i) {
            return new File(directory, key + "." + i + ".tmp");
        }

当我们调用save的时候,我们就将输出流和该文件绑定起来了。这里面还有些什么dirtyFile和cleanFile的
处理,就不一一详述了。
本地缓存
LruMemoryCache
显示
BitMapDisplayer 反正最后走到了ViewAware里面,进行了一个判断

if (Looper.myLooper() == Looper.getMainLooper()) {

先说到这吧,最重要的是把我思路,整个流程到底是怎么走的,然后再分析一些细节的处理,如果有特殊需求
可以灵活的更改逻辑。

你可能感兴趣的:(开源项目)