• 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从网络下载,放入磁盘缓存,内存缓存,最后显示

  • 相关阅读:
    超好看的UI配色网站汇总~
    JS获取非行内样式
    最近看到的一些不错前端面试题目
    指令
    $filter $watch
    学习学习学习
    Mongoose by时间查询
    AngularJs 学习 笔记 4 foreach
    AngularJs 学习 笔记 3
    AngularJs 学习 笔记 2
  • 原文地址:https://www.cnblogs.com/gatsbydhn/p/5398104.html
Copyright © 2020-2023  润新知