从源代码分析Android-Universal-Image-Loader图片下载技巧

本文涉及的产品
云解析 DNS,旗舰版 1个月
全局流量管理 GTM,标准版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
简介:

在手机上尤其需要考虑网络对图片下载的影响,常见的情况是在2G网络、在3G网络需要不同的下载策略,也就是说在慢速网络与快速网络中下载需要考虑不同的策略。一种常见的策略就是Android客户端和服务端相配合的方式,针对慢速网络对图片进行优化(让图片的质量低一点,保证能下载),但是这种情况不在本文讨论的范围中。在本文中主要讨论针对不能改变的服务器图片质量(图片的大小 xx KB),Android-Universal-Image-Loader所采取的下载策略。

    需要具体考虑网络情况有:快速、慢速、无网络权限。针对这三种情况,在UIL中分别定义了三种策略。还是让我们从代码入手看看。在《从代码分析Android-Universal-Image-Loader的图片加载、显示流程》我们分析了图片的下载是从LoadAndDisplayImageTask.decodeImage(…)中开始的,其中函数内部调用了getDownloader(),然后在ImageDecoder接口的实现类(BaseImageDecoder)中获取InputStream实现图片的下载和解析。跟进去getDownloader()中看看。

复制代码
private ImageDownloader getDownloader() {
        ImageDownloader d;
        if (engine.isNetworkDenied()) {
            d = networkDeniedDownloader;
        } else if (engine.isSlowNetwork()) {
            d = slowNetworkDownloader;
        } else {
            d = downloader;
        }
        return d;
    }
复制代码

networkDeniedDownloader、slowNetworkDownloader、downloader究竟是什么?在LoadAndDisplayImageTask的构造函数中我们看到他们实际是来源于ImageLoaderConfiguration类中对应的networkDeniedDownloader、slowNetworkDownloader、downloader。在ImageLoaderConfiguration的构造函数总,我们发现downloader来源于ImageLoaderConfiguration.Builder,分析后发现它就是一个BaseImageDownloader对象(最后在DefaultConfigurationFactory.createImageDownloade(…)中被初始化)。回到ImageLoaderConfiguration类的构造函数中(如下所示)

 

复制代码
private ImageLoaderConfiguration(final Builder builder) {
        resources = builder.context.getResources();
        maxImageWidthForMemoryCache = builder.maxImageWidthForMemoryCache;
        maxImageHeightForMemoryCache = builder.maxImageHeightForMemoryCache;
        maxImageWidthForDiskCache = builder.maxImageWidthForDiskCache;
        maxImageHeightForDiskCache = builder.maxImageHeightForDiskCache;
        processorForDiskCache = builder.processorForDiskCache;
        taskExecutor = builder.taskExecutor;
        taskExecutorForCachedImages = builder.taskExecutorForCachedImages;
        threadPoolSize = builder.threadPoolSize;
        threadPriority = builder.threadPriority;
        tasksProcessingType = builder.tasksProcessingType;
        diskCache = builder.diskCache;
        memoryCache = builder.memoryCache;
        defaultDisplayImageOptions = builder.defaultDisplayImageOptions;
        downloader 
=
 builder.downloader;
        decoder = builder.decoder;

        customExecutor = builder.customExecutor;
        customExecutorForCachedImages = builder.customExecutorForCachedImages;

        networkDeniedDownloader 
new  NetworkDeniedImageDownloader(downloader); slowNetworkDownloader new
 SlowNetworkImageDownloader(downloader);

        L.writeDebugLogs(builder.writeLogs);
    }
复制代码

我们发现networkDeniedDownloader、slowNetworkDownloader都依赖与downloader对象,猜想这两个类应该是对BaseImageDownloader的一个包装。下面我们贴出NetworkDeniedImageDownloader、SlowNetworkImageDownloader的代码(它们在com.nostra13.universalimageloader.core.ImageLoaderConfiguration类中)

复制代码
/**
     * Decorator. Prevents downloads from network (throws {@link IllegalStateException exception}).<br />
     * In most cases this downloader shouldn't be used directly.
     *
     * @author Sergey Tarasevich (nostra13[at]gmail[dot]com)
     * @since 1.8.0
     */
    private static class NetworkDeniedImageDownloader implements ImageDownloader {

        private final ImageDownloader wrappedDownloader;

        public NetworkDeniedImageDownloader(ImageDownloader wrappedDownloader) {
            this.wrappedDownloader = wrappedDownloader;
        }

        @Override
        public InputStream getStream(String imageUri, Object extra) throws IOException {
            switch (Scheme.ofUri(imageUri)) {
                case HTTP:
                case HTTPS:
                    throw new IllegalStateException();
                default:
                    return wrappedDownloader.getStream(imageUri, extra);
            }
        }
    }

    /**
     * Decorator. Handles <a href="http://code.google.com/p/android/issues/detail?id=6066">this problem</a> on slow networks
     * using {@link com.nostra13.universalimageloader.core.assist.FlushedInputStream}.
     *
     * @author Sergey Tarasevich (nostra13[at]gmail[dot]com)
     * @since 1.8.1
     */
    private static class SlowNetworkImageDownloader implements ImageDownloader {

        private final ImageDownloader wrappedDownloader;

        public SlowNetworkImageDownloader(ImageDownloader wrappedDownloader) {
            this.wrappedDownloader = wrappedDownloader;
        }

        @Override
        public InputStream getStream(String imageUri, Object extra) throws IOException {
            InputStream imageStream = wrappedDownloader.getStream(imageUri, extra);
            switch (Scheme.ofUri(imageUri)) {
                case HTTP:
                case HTTPS:
                    return new FlushedInputStream(imageStream);
                default:
                    return imageStream;
            }
        }
    }
复制代码

先看到NetworkDeniedImageDownloader类,这个类中由于对应的是没有网络访问权限(android.permission.INTERNET)的情况,这种情况下Http和Https自然就不能使用了,其他情况(如从本地资源中获取图片)还是可以的。NetworkDeniedImageDownloader.wrappedDownloader对象是什么呢?其实就是我们刚刚ImageLoaderConfiguration构造函数中传入的BaseImageDownloader对象。在看看这个类中的getStream(…)方法。

复制代码
@Override
    public InputStream getStream(String imageUri, Object extra) throws IOException {
        switch (Scheme.ofUri(imageUri)) {
            case HTTP:
            case HTTPS:
                return getStreamFromNetwork(imageUri, extra);
            case FILE:
                return getStreamFromFile(imageUri, extra);
            case CONTENT:
                return getStreamFromContent(imageUri, extra);
            case ASSETS:
                return getStreamFromAssets(imageUri, extra);
            case DRAWABLE:
                return getStreamFromDrawable(imageUri, extra);
            case UNKNOWN:
            default:
                return getStreamFromOtherSource(imageUri, extra);
        }
    }
复制代码

从这个函数中,我们可以看到UIL通过Scheme.ofUri(…)分析imageUri,根据ImageUri的类型选择对应的方法进行处理。通过分析Scheme类,我们发现UIL支持以下几种图片获取方式HTTP, HTTPS, FILE, CONTENT, ASSETS, DRAWABLE。

接下来,我们分析一下SlowNetworkImageDownloader.getStream(…)方法,每一次图片的下载最终都会通过BitmapFactory.decodeStream解析成Bitmap,供ImageView显示。我们可以发现这个方法针对慢速网络使用FlushedInputStream来处理。使用这个类的原因是因为在慢速网络中,BitmapFactory.decodeStream无法正确解析完整的图片。具体的可以参考StackOverFlow上的帖子《BitmapFactory.decodeStream always returns null and skia decoder shows decode returned false》和一个Google上的Bug 报告《BitmapFactory.decodeStream() fails if InputStream.skip() does not skip fully》。

网速不慢的下载就直接使用BaseImageDownloader.getStream(…)方法了。

至此,我们已经分析了UIL中图片下载技巧,最后梳理一下。为了应对慢速、正常、访问受限网络,UIL分别 使用了SlowNetworkDownloader、BaseImageLoader、NetworkDeniedDownloader来应对这些策略,在LoadAndDisplayImageTask.getDownloader(…)中通过获取对应的downloader,最后通过LoadAndDisplayImageTask.decodeImage(…)将图片解析出来。

本文转自陈哈哈博客园博客,原文链接http://www.cnblogs.com/kissazi2/p/3911472.html如需转载请自行联系原作者


kissazi2

相关文章
|
19天前
|
开发框架 前端开发 Android开发
Flutter 与原生模块(Android 和 iOS)之间的通信机制,包括方法调用、事件传递等,分析了通信的必要性、主要方式、数据传递、性能优化及错误处理,并通过实际案例展示了其应用效果,展望了未来的发展趋势
本文深入探讨了 Flutter 与原生模块(Android 和 iOS)之间的通信机制,包括方法调用、事件传递等,分析了通信的必要性、主要方式、数据传递、性能优化及错误处理,并通过实际案例展示了其应用效果,展望了未来的发展趋势。这对于实现高效的跨平台移动应用开发具有重要指导意义。
83 4
|
1月前
|
安全 Android开发 数据安全/隐私保护
深入探讨iOS与Android系统安全性对比分析
在移动操作系统领域,iOS和Android无疑是两大巨头。本文从技术角度出发,对这两个系统的架构、安全机制以及用户隐私保护等方面进行了详细的比较分析。通过深入探讨,我们旨在揭示两个系统在安全性方面的差异,并为用户提供一些实用的安全建议。
|
3月前
|
开发工具 Android开发 Swift
安卓与iOS开发环境对比分析
在移动应用开发的广阔舞台上,安卓和iOS这两大操作系统无疑是主角。它们各自拥有独特的特点和优势,为开发者提供了不同的开发环境和工具。本文将深入浅出地探讨安卓和iOS开发环境的主要差异,包括开发工具、编程语言、用户界面设计、性能优化以及市场覆盖等方面,旨在帮助初学者更好地理解两大平台的开发特点,并为他们选择合适的开发路径提供参考。通过比较分析,我们将揭示不同环境下的开发实践,以及如何根据项目需求和目标受众来选择最合适的开发平台。
51 2
|
11天前
|
Java 开发工具 Android开发
安卓与iOS开发环境对比分析
在移动应用开发的广阔天地中,安卓和iOS两大平台各自占据半壁江山。本文深入探讨了这两个平台的开发环境,从编程语言、开发工具到用户界面设计等多个角度进行比较。通过实际案例分析和代码示例,我们旨在为开发者提供一个清晰的指南,帮助他们根据项目需求和个人偏好做出明智的选择。无论你是初涉移动开发领域的新手,还是寻求跨平台解决方案的资深开发者,这篇文章都将为你提供宝贵的信息和启示。
20 8
|
2月前
|
缓存 Java Shell
Android 系统缓存扫描与清理方法分析
Android 系统缓存从原理探索到实现。
67 15
Android 系统缓存扫描与清理方法分析
|
14天前
|
安全 Android开发 数据安全/隐私保护
深入探索Android与iOS系统安全性的对比分析
在当今数字化时代,移动操作系统的安全已成为用户和开发者共同关注的重点。本文旨在通过比较Android与iOS两大主流操作系统在安全性方面的差异,揭示两者在设计理念、权限管理、应用审核机制等方面的不同之处。我们将探讨这些差异如何影响用户的安全体验以及可能带来的风险。
18 1
|
2月前
|
存储 Linux Android开发
Android底层:通熟易懂分析binder:1.binder准备工作
本文详细介绍了Android Binder机制的准备工作,包括打开Binder驱动、内存映射(mmap)、启动Binder主线程等内容。通过分析系统调用和进程与驱动层的通信,解释了Binder如何实现进程间通信。文章还探讨了Binder主线程的启动流程及其在进程通信中的作用,最后总结了Binder准备工作的调用时机和重要性。
Android底层:通熟易懂分析binder:1.binder准备工作
|
3月前
|
安全 Android开发 数据安全/隐私保护
探索安卓与iOS的安全性差异:技术深度分析与实践建议
本文旨在深入探讨并比较Android和iOS两大移动操作系统在安全性方面的不同之处。通过详细的技术分析,揭示两者在架构设计、权限管理、应用生态及更新机制等方面的安全特性。同时,针对这些差异提出针对性的实践建议,旨在为开发者和用户提供增强移动设备安全性的参考。
145 3
|
2月前
|
开发工具 Android开发 Swift
安卓与iOS开发环境的差异性分析
【10月更文挑战第8天】 本文旨在探讨Android和iOS两大移动操作系统在开发环境上的不同,包括开发语言、工具、平台特性等方面。通过对这些差异性的分析,帮助开发者更好地理解两大平台,以便在项目开发中做出更合适的技术选择。
|
3月前
|
安全 Linux Android开发
探索安卓与iOS的安全性差异:技术深度分析
本文深入探讨了安卓(Android)和iOS两个主流操作系统平台在安全性方面的不同之处。通过比较它们在架构设计、系统更新机制、应用程序生态和隐私保护策略等方面的差异,揭示了每个平台独特的安全优势及潜在风险。此外,文章还讨论了用户在使用这些设备时可以采取的一些最佳实践,以增强个人数据的安全。