Android进阶-UIL分析

一、基本组件:

  1. ImageLoaderEngine:任务分发器,负责分发 LoadAndDisplayImageTask和ProcessAndDisplayImageTask 给线程池执行
  2. LoadAndDisplayImageTask:用于加载显示图片的任务
  3. ProcessAndDisplayImageTask:用于处理并显示图像的任务
  4. ImageAware:显示图片的对象,可以是ImageView
  5. DiskCache:
  6. ImageDecoder:图片解码器,将InputStream转换为Bitmap对象
  7. MemoryCache:内存缓存
  8. BitmapProcessor:负责BItmap进行处理
  9. BitmapDisplayer:将Bitmap显示在对应的ImageAware上

二、ImageLoader.displayImage()分析:

  1 public void displayImage(String uri, ImageAware imageAware, DisplayImageOptions options,
  2             ImageSize targetSize, ImageLoadingListener listener, ImageLoadingProgressListener progressListener) {
  3         //检测参数有效性
  4         checkConfiguration();
  5         if (imageAware == null) {
  6             throw new IllegalArgumentException(ERROR_WRONG_ARGUMENTS);
  7         }
  8         if (listener == null) {
  9             listener = defaultListener;
 10         }
 11         if (options == null) {
 12             options = configuration.defaultDisplayImageOptions;
 13         }
 14
 15         if (TextUtils.isEmpty(uri)) {
 16             engine.cancelDisplayTaskFor(imageAware);
 17             listener.onLoadingStarted(uri, imageAware.getWrappedView());
 18             if (options.shouldShowImageForEmptyUri()) {
 19                 imageAware.setImageDrawable(options.getImageForEmptyUri(configuration.resources));
 20             } else {
 21                 imageAware.setImageDrawable(null);
 22             }
 23             listener.onLoadingComplete(uri, imageAware.getWrappedView(), null);
 24             return;
 25         }
 26
 27         if (targetSize == null) {
 28             targetSize = ImageSizeUtils.defineTargetSizeForView(imageAware, configuration.getMaxImageSize());
 29         }
 30         String memoryCacheKey = MemoryCacheUtils.generateKey(uri, targetSize);
 31         engine.prepareDisplayTaskFor(imageAware, memoryCacheKey);
 32
 33         listener.onLoadingStarted(uri, imageAware.getWrappedView());
 34
 35         //尝试从内存中获取缓存,使用了MemoryCache组件
 36         Bitmap bmp = configuration.memoryCache.get(memoryCacheKey);
 37         if (bmp != null && !bmp.isRecycled()) {
 38             //若已在内存缓存
 39             L.d(LOG_LOAD_IMAGE_FROM_MEMORY_CACHE, memoryCacheKey);
 40             //如果需要处理,则调用ProcessAndDisplayImageTask.run()Bitmap进行处理
 41             if (options.shouldPostProcess()) {
 42                 ImageLoadingInfo imageLoadingInfo = new ImageLoadingInfo(uri, imageAware, targetSize, memoryCacheKey,
 43                         options, listener, progressListener, engine.getLockForUri(uri));
 44                 ProcessAndDisplayImageTask displayTask = new ProcessAndDisplayImageTask(engine, bmp, imageLoadingInfo,
 45                         defineHandler(options));
 46                 if (options.isSyncLoading()) {
 47                     //处理Bitmap
 48                     displayTask.run();
 49                 } else {
 50                     engine.submit(displayTask);
 51                 }
 52             } else {
 53                 //无需处理Bitmap,则调用BitmapDisplayer组件将bitmap显示在imageAware上
 54                 options.getDisplayer().display(bmp, imageAware, LoadedFrom.MEMORY_CACHE);
 55                 //回调加载完成
 56                 listener.onLoadingComplete(uri, imageAware.getWrappedView(), bmp);
 57             }
 58         } else {
 59             //若内存中无该缓存
 60             if (options.shouldShowImageOnLoading()) {
 61                 imageAware.setImageDrawable(options.getImageOnLoading(configuration.resources));
 62             } else if (options.isResetViewBeforeLoading()) {
 63                 imageAware.setImageDrawable(null);
 64             }
 65             //封装加载信息
 66             ImageLoadingInfo imageLoadingInfo = new ImageLoadingInfo(uri, imageAware, targetSize, memoryCacheKey,
 67                     options, listener, progressListener, engine.getLockForUri(uri));
 68             //创建LoadAndDisplayImageTask组件
 69             LoadAndDisplayImageTask displayTask = new LoadAndDisplayImageTask(engine, imageLoadingInfo,
 70                     defineHandler(options));
 71             if (options.isSyncLoading()) {
 72                 //从磁盘或网络加载,下面会分析
 73                 displayTask.run();
 74             } else {
 75                 engine.submit(displayTask);
 76             }
 77         }
 78     }
 79
 80
 81
 82 @Override
 83     public void run() {
 84         if (waitIfPaused()) return;
 85         if (delayIfNeed()) return;
 86
 87         ReentrantLock loadFromUriLock = imageLoadingInfo.loadFromUriLock;
 88         L.d(LOG_START_DISPLAY_IMAGE_TASK, memoryCacheKey);
 89         if (loadFromUriLock.isLocked()) {
 90             L.d(LOG_WAITING_FOR_IMAGE_LOADED, memoryCacheKey);
 91         }
 92
 93         loadFromUriLock.lock();
 94         Bitmap bmp;
 95         try {
 96             checkTaskNotActual();
 97             //尝试从内存获取
 98             bmp = configuration.memoryCache.get(memoryCacheKey);
 99             if (bmp == null || bmp.isRecycled()) {
100                 //未在内存缓存,下面将分析tryLoadBitmap
101                 bmp = tryLoadBitmap();
102                 if (bmp == null) return; // listener callback already was fired
103
104                 checkTaskNotActual();
105                 checkTaskInterrupted();
106
107                 if (options.shouldPreProcess()) {
108                     L.d(LOG_PREPROCESS_IMAGE, memoryCacheKey);
109                     bmp = options.getPreProcessor().process(bmp);
110                     if (bmp == null) {
111                         L.e(ERROR_PRE_PROCESSOR_NULL, memoryCacheKey);
112                     }
113                 }
114
115                 if (bmp != null && options.isCacheInMemory()) {
116                     L.d(LOG_CACHE_IMAGE_IN_MEMORY, memoryCacheKey);
117                     configuration.memoryCache.put(memoryCacheKey, bmp);
118                 }
119             } else {
120                 loadedFrom = LoadedFrom.MEMORY_CACHE;
121                 L.d(LOG_GET_IMAGE_FROM_MEMORY_CACHE_AFTER_WAITING, memoryCacheKey);
122             }
123
124             if (bmp != null && options.shouldPostProcess()) {
125                 L.d(LOG_POSTPROCESS_IMAGE, memoryCacheKey);
126                 bmp = options.getPostProcessor().process(bmp);
127                 if (bmp == null) {
128                     L.e(ERROR_POST_PROCESSOR_NULL, memoryCacheKey);
129                 }
130             }
131             checkTaskNotActual();
132             checkTaskInterrupted();
133         } catch (TaskCancelledException e) {
134             fireCancelEvent();
135             return;
136         } finally {
137             loadFromUriLock.unlock();
138         }
139
140         DisplayBitmapTask displayBitmapTask = new DisplayBitmapTask(bmp, imageLoadingInfo, engine, loadedFrom);
141         runTask(displayBitmapTask, syncLoading, handler, engine);
142     }
143
144
145     private Bitmap tryLoadBitmap() throws TaskCancelledException {
146         Bitmap bitmap = null;
147         try {
148             //调用DiskCache组件尝试从磁盘获取缓存
149             File imageFile = configuration.diskCache.get(uri);
150             if (imageFile != null && imageFile.exists() && imageFile.length() > 0) {
151                 //若已在磁盘缓存
152                 L.d(LOG_LOAD_IMAGE_FROM_DISK_CACHE, memoryCacheKey);
153                 loadedFrom = LoadedFrom.DISC_CACHE;
154
155                 checkTaskNotActual();
156                 //将磁盘文件转换为bitmap对象
157                 bitmap = decodeImage(Scheme.FILE.wrap(imageFile.getAbsolutePath()));
158             }
159             if (bitmap == null || bitmap.getWidth() <= 0 || bitmap.getHeight() <= 0) {
160                 //若不在磁盘缓存
161                 L.d(LOG_LOAD_IMAGE_FROM_NETWORK, memoryCacheKey);
162                 loadedFrom = LoadedFrom.NETWORK;
163
164                 String imageUriForDecoding = uri;
165                 //从网络加载,并放入磁盘缓存,下面分析
166                 if (options.isCacheOnDisk() && tryCacheImageOnDisk()) {
167                     imageFile = configuration.diskCache.get(uri);
168                     if (imageFile != null) {
169                         imageUriForDecoding = Scheme.FILE.wrap(imageFile.getAbsolutePath());
170                     }
171                 }
172
173                 checkTaskNotActual();
174                 bitmap = decodeImage(imageUriForDecoding);
175
176                 if (bitmap == null || bitmap.getWidth() <= 0 || bitmap.getHeight() <= 0) {
177                     fireFailEvent(FailType.DECODING_ERROR, null);
178                 }
179             }
180         } catch (IllegalStateException e) {
181             fireFailEvent(FailType.NETWORK_DENIED, null);
182         } catch (TaskCancelledException e) {
183             throw e;
184         } catch (IOException e) {
185             L.e(e);
186             fireFailEvent(FailType.IO_ERROR, e);
187         } catch (OutOfMemoryError e) {
188             L.e(e);
189             fireFailEvent(FailType.OUT_OF_MEMORY, e);
190         } catch (Throwable e) {
191             L.e(e);
192             fireFailEvent(FailType.UNKNOWN, e);
193         }
194         return bitmap;
195     }
196
197
198 private boolean tryCacheImageOnDisk() throws TaskCancelledException {
199         L.d(LOG_CACHE_IMAGE_ON_DISK, memoryCacheKey);
200
201         boolean loaded;
202         try {
203             //下载图片,下面分析
204             loaded = downloadImage();
205             if (loaded) {
206                 int width = configuration.maxImageWidthForDiskCache;
207                 int height = configuration.maxImageHeightForDiskCache;
208                 if (width > 0 || height > 0) {
209                     L.d(LOG_RESIZE_CACHED_IMAGE_FILE, memoryCacheKey);
210                     resizeAndSaveImage(width, height); // TODO : process boolean result
211                 }
212             }
213         } catch (IOException e) {
214             L.e(e);
215             loaded = false;
216         }
217         return loaded;
218     }
219
220     private boolean downloadImage() throws IOException {
221         //获取输入流
222         InputStream is = getDownloader().getStream(uri, options.getExtraForDownloader());
223         if (is == null) {
224             L.e(ERROR_NO_IMAGE_STREAM, memoryCacheKey);
225             return false;
226         } else {
227             try {
228                 //保存到磁盘缓存
229                 return configuration.diskCache.save(uri, is, this);
230             } finally {
231                 IoUtils.closeSilently(is);
232             }
233         }
234     }

大概流程如下:

  1. 尝试从内存缓存获取数据

    1. 若已缓存,处理该Bitmap,交给BitmapDisplayer显示
    2. 若不在,则从磁盘获取
      1. 若在磁盘中,则解析文件到Bitmap,缓存到内存缓存,显示
      2. 若不在磁盘中,交个ImageDownLoader从网络下载,放入磁盘缓存,内存缓存,最后显示

时间: 2024-11-05 22:01:14

Android进阶-UIL分析的相关文章

Android 进阶学习:事件分发机制全然解析,带你从源代码的角度彻底理解(上)

http://blog.csdn.net/guolin_blog/article/details/9097463 事实上我一直准备写一篇关于Android事件分发机制的文章,从我的第一篇博客開始,就零零散散在好多地方使用到了Android事件分发的知识.也有好多朋友问过我各种问题,比方:onTouch和onTouchEvent有什么差别,又该怎样使用?为什么给ListView引入了一个滑动菜单的功能,ListView就不能滚动了?为什么图片轮播器里的图片使用Button而不用ImageView?

我的Android进阶之旅------&gt;Android疯狂连连看游戏的实现之实现游戏逻辑(五)

在上一篇<我的Android进阶之旅------>Android疯狂连连看游戏的实现之加载界面图片和实现游戏Activity(四)>中提到的两个类: GameConf:负责管理游戏的初始化设置信息. GameService:负责游戏的逻辑实现. 其中GameConf的代码如下:cn\oyp\link\utils\GameConf.java package cn.oyp.link.utils; import android.content.Context; /** * 保存游戏配置的对象

Android进阶——多线程系列之Thread、Runnable、Callable、Future、FutureTask

多线程系列之Thread.Runnable.Callable.Future.FutureTask 前言 多线程一直是初学者最抵触的东西,如果你想进阶的话,那必须闯过这道难关,特别是多线程中Thread.Runnable.Callable.Future.FutureTask这几个类往往是初学者容易搞混的.这里先总结这几个类特点和区别,让大家带着模糊印象来学习这篇文章 Thread.Runnable.Callable:都是线程 Thread特点:提供了线程等待.线程睡眠.线程礼让等操作 Runnab

我的Android进阶之旅------&gt;经典的大牛博客推荐(排名不分先后)!!

本文来自:http://blog.csdn.net/ouyang_peng/article/details/11358405 今天看到一篇文章,收藏了很多大牛的博客,在这里分享一下 谦虚的天下 柳志超博客 Android中文Wiki AndroidStudio-NDK开发-移动开发团队谦虚的天下 - 博客园gundumw100博客 - android进阶分类文章列表 - ITeye技术网站CSDN博文精选:Android系列开发博客资源汇总 - CSDN.NET - CSDN资讯Android笔

Android进阶之自定义View实战(二)九宫格手势解锁实现

一.引言 在上篇博客Android进阶之自定义View实战(一)仿iOS UISwitch控件实现中我们主要介绍了自定义View的最基本的实现方法.作为自定义View的入门篇,仅仅介绍了Canvas的基本使用方法,而对用户交互层面仅仅处理了单击事件接口,在实际的业务中,常常涉及到手势操作,本篇博客以九宫格手势解锁View为例,来说明自定义View如何根据需求处理用户的手势操作.虽然九宫格手势解锁自定义View网上资料有很多,实现原理大同小异,但这里我只是根据自己觉得最优的思路来实现它,目的是让更

Android 面试题总结之Android 进阶(二)

Android 之美 从0到1 之Android 进阶(二) 在上一章节中<Android 之美 从0到1 之Android 进阶(一)>中我们已经理解了一些View的基本知识并且知道如何自定义View.那么本章节将继续深入理解View,关于View的绘制流程,View的事件分发.刷新机制等等. 在阅读过程中有任何问题,请及时联系.如需转载请注明 fuchenxuan blog 本章系<Android 之美 从0到1 – 高手之路>Android 深入理解View的绘制流程. An

Android进阶之路(1)-详解MVC

最近因为换工作的原因没有写博客,现在慢慢稳定了,我准备写一些关于Android 进阶的文章,也是为了督促自己学习,大家一起进步! 今天详细的分析一下Android APP架构之一:MVC ### MVC简介 >[MVC](https://baike.baidu.com/item/MVC)全名是Model View Controller,是模型(model)-视图(view)-控制器(controller)的缩写,一种软件设计典范,用一种业务逻辑.数据.界面显示分离的方法组织代码,将业务逻辑聚集到

我的Android进阶之旅------&gt;Java字符串格式化方法String.format()格式化float型时小数点变成逗号问题

今天接到一个波兰的客户说有个APP在英文状态下一切运行正常,但是当系统语言切换到波兰语言的时候,程序奔溃了.好吧,又是我来维护. 好吧,先把系统语言切换到波兰语,切换到波兰语的方法查看文章 我的Android进阶之旅------>Android[设置]-[语言和输入法]-[语言]列表中找到相应语言所对应的列表项 地址:http://blog.csdn.net/ouyang_peng/article/details/50209789 ================================

Cordova Android源码分析系列一(项目总览和CordovaActivity分析)

PhoneGap/Cordova是一个专业的移动应用开发框架,是一个全面的WEB APP开发的框架,提供了以WEB形式来访问终端设备的API的功能.这对于采用WEB APP进行开发者来说是个福音,这可以避免了原生开发的某些功能.Cordova 只是个原生外壳,app的内核是一个完整的webapp,需要调用的原生功能将以原生插件的形式实现,以暴露js接口的方式调用. Cordova Android项目是Cordova Android原生部分的Java代码实现,提供了Android原生代码和上层We