• linkedu视频
  • 平面设计
  • 电脑入门
  • 操作系统
  • 办公应用
  • 电脑硬件
  • 动画设计
  • 3D设计
  • 网页设计
  • CAD设计
  • 影音处理
  • 数据库
  • 程序设计
  • 认证考试
  • 信息管理
  • 信息安全
菜单
linkedu.com
  • 网页制作
  • 数据库
  • 程序设计
  • 操作系统
  • CMS教程
  • 游戏攻略
  • 脚本语言
  • 平面设计
  • 软件教程
  • 网络安全
  • 电脑知识
  • 服务器
  • 视频教程
  • JavaScript
  • ASP.NET
  • PHP
  • 正则表达式
  • AJAX
  • JSP
  • ASP
  • Flex
  • XML
  • 编程技巧
  • Android
  • swift
  • C#教程
  • vb
  • vb.net
  • C语言
  • Java
  • Delphi
  • 易语言
  • vc/mfc
  • 嵌入式开发
  • 游戏开发
  • ios
  • 编程问答
  • 汇编语言
  • 微信小程序
  • 数据结构
  • OpenGL
  • 架构设计
  • qt
  • 微信公众号
您的位置:首页 > 程序设计 >Android > Android-Universal-Image-Loader (图片异步加载缓存库)的源码解读

Android-Universal-Image-Loader (图片异步加载缓存库)的源码解读

作者:网友 字体:[增加 减小] 来源:互联网 时间:2017-05-26

网友通过本文主要向大家介绍了安卓中异步图片缓存,三相异步电动机,三相异步电机,异步电动机,异步社区等相关知识,希望对您有所帮助,也希望大家支持linkedu.com www.linkedu.com

Android-Universal-Image-Loader (图片异步加载缓存库)的源码解读


前言:

在Android开发中,对于图片的加载可以说是个老生常谈的问题了,图片加载是一个比较坑的地方,处理不好,会有各种奇怪的问题,比如 加载导致界面卡顿,程序crash。
因此 如何高效的加载大量图片,以及如何加载大分辨率的图片到内存,是我们想要开发一款优质app时不得不去面对与解决的问题。
通常开发中,我们只有两种选择:① 使用开源框架 ②自己去实现处理图片的加载与缓存。
通常一开始让我们自己去写,我们会无从下手,因此先去分析一下开源的思路,对我们的成长很有必要。
目前使用频率较高的图片缓存框架有 Universal-Image-Loader、android-Volley、Picasso、Fresco和Glide五大Android开源组件。
首先排除android-Volley 孰优孰劣,后面再去验证,剩下的四种对于 图片加载缓存的思想,从大方向上应该是类似的
而Android-Universal-Image-Loader 作为一款比较经典的框架,从早期到现在一直都比较常见,这里就拿Android-Universal-Image-Loader 来看一下它对图片处理的思想,以帮助我们理解,以便于我们也能写出类似的框架。

关于使用配置请看Android-Universal-Image-Loader (图片异步加载缓存库)的使用配置

正文:

 </div>

一 工作流程

前面介绍了如何在我们的项目中使用Android-Universal-Image-Loader,本文看一下UIL的工作过程。

在看之前我们先看一下官方的这张图片,它代表着所有条件下的执行流程:

\

图片给出的加载过程分别对应三种情况:

1.当内存中有该 bitmap 时,直接显示。

2.当本地有该图片时,加载进内存,然后显示。

3. 内存本地都没有时,请求网络,下载到本地,接下来加载进内存,然后显示。

 

过程分析:</div>

 

最终展示图片还是调用的ImageLoader 这个类中的 display() 方法,那么我们就把注意力集中到ImageLoader 这个类上,看下display()内部怎么实现的。

 

	public void displayImage(String uri, ImageAware imageAware, DisplayImageOptions options,
			ImageLoadingListener listener, ImageLoadingProgressListener progressListener) {
		// 首先检查初始化配置,configuration == null 抛出异常
		checkConfiguration();
		if (imageAware == null) {
			throw new IllegalArgumentException(ERROR_WRONG_ARGUMENTS);
		}
		if (listener == null) {
			listener = defaultListener;
		}
		if (options == null) {
			options = configuration.defaultDisplayImageOptions;
		}
		// 当  目标uri "" 时这种情况的处理
		if (TextUtils.isEmpty(uri)) {
			engine.cancelDisplayTaskFor(imageAware);
			listener.onLoadingStarted(uri, imageAware.getWrappedView());
			if (options.shouldShowImageForEmptyUri()) {
				imageAware.setImageDrawable(options.getImageForEmptyUri(configuration.resources));
			} else {
				imageAware.setImageDrawable(null);
			}
			listener.onLoadingComplete(uri, imageAware.getWrappedView(), null);
			return;
		}
		// 根据  配置的大小与图片实际大小得出 图片尺寸
		ImageSize targetSize = ImageSizeUtils.defineTargetSizeForView(imageAware, configuration.getMaxImageSize());
		String memoryCacheKey = MemoryCacheUtils.generateKey(uri, targetSize);
		engine.prepareDisplayTaskFor(imageAware, memoryCacheKey);

		listener.onLoadingStarted(uri, imageAware.getWrappedView());
		// 首先从内存中取,看是否加载过,有缓存直接用
		Bitmap bmp = configuration.memoryCache.get(memoryCacheKey);
		if (bmp != null && !bmp.isRecycled()) {
			L.d(LOG_LOAD_IMAGE_FROM_MEMORY_CACHE, memoryCacheKey);

			if (options.shouldPostProcess()) {
				ImageLoadingInfo imageLoadingInfo = new ImageLoadingInfo(uri, imageAware, targetSize, memoryCacheKey,
						options, listener, progressListener, engine.getLockForUri(uri));
				ProcessAndDisplayImageTask displayTask = new ProcessAndDisplayImageTask(engine, bmp, imageLoadingInfo,
						defineHandler(options));
				if (options.isSyncLoading()) {
					displayTask.run();
				} else {
					engine.submit(displayTask);
				}
			} else {
				options.getDisplayer().display(bmp, imageAware, LoadedFrom.MEMORY_CACHE);
				listener.onLoadingComplete(uri, imageAware.getWrappedView(), bmp);
			}
		} else {
			// 没有缓存
			if (options.shouldShowImageOnLoading()) {
				imageAware.setImageDrawable(options.getImageOnLoading(configuration.resources));
			} else if (options.isResetViewBeforeLoading()) {
				imageAware.setImageDrawable(null);
			}
			
			ImageLoadingInfo imageLoadingInfo = new ImageLoadingInfo(uri, imageAware, targetSize, memoryCacheKey,
					options, listener, progressListener, engine.getLockForUri(uri));
			LoadAndDisplayImageTask displayTask = new LoadAndDisplayImageTask(engine, imageLoadingInfo,
					defineHandler(options));
			if (options.isSyncLoading()) {
				displayTask.run();
			} else {
				engine.submit(displayTask);
			}
		}
	}

可以看到这个方法还不长,大体流程也向前面图中描述的:

 

首先判断传入的目标url 是" ",如果空,是否配置了默认的图片,接下来重点在url 是合法的情况下,去加载bitmap,首先从内存中去取,看能否取到(如果前面加载到内存,并且缓存过,没有被移除,则可以取到),如果取到则直接展示就可以了。

 

如果没有在内存中取到,接下来执行LoadAndDisplayImageTask 这个任务,主要还是看run()方法的执行过程:

 

@Override
	public void run() {
		if (waitIfPaused()) return;
		if (delayIfNeed()) return;

		ReentrantLock loadFromUriLock = imageLoadingInfo.loadFromUriLock;
		L.d(LOG_START_DISPLAY_IMAGE_TASK, memoryCacheKey);
		if (loadFromUriLock.isLocked()) {
			L.d(LOG_WAITING_FOR_IMAGE_LOADED, memoryCacheKey);
		}

		loadFromUriLock.lock();
		Bitmap bmp;
		try {
			checkTaskNotActual();
			bmp = configuration.memoryCache.get(memoryCacheKey);
			if (bmp == null || bmp.isRecycled()) { 
				// cache 中没有,下载
				bmp = tryLoadBitmap();
				if (bmp == null) return; // listener callback already was fired

				checkTaskNotActual();
				checkTaskInterrupted();

				if (options.shouldPreProcess()) {
					L.d(LOG_PREPROCESS_IMAGE, memoryCacheKey);
					bmp = options.getPreProcessor().process(bmp);
					if (bmp == null) {
						L.e(ERROR_PRE_PROCESSOR_NULL, memoryCacheKey);
					}
				}
				// 加入到内存的缓存
				if (bmp != null && options.isCacheInMemory()) {
					L.d(LOG_CACHE_IMAGE_IN_MEMORY, memoryCacheKey);
				 //LruMemoryCache
					configuration.memoryCache.put(memoryCacheKey, bmp);
				}
			} else {
				loadedFrom = LoadedFrom.MEMORY_CACHE;
				L.d(LOG_GET_IMAGE_FROM_MEMORY_CACHE_AFTER_WAITING, memoryCacheKey);
			}

			if (bmp != null && options.shouldPostProcess()) {
				L.d(LOG_POSTPROCESS_IMAGE, memoryCacheKey);
				bmp = options.getPostProcessor().process(bmp);
				if (bmp == null) {
					L.e(ERROR_POST_PROCESSOR_NULL, memoryCacheKey);
				}
			}
			checkTaskNotActual();
			checkTaskInterrupted();
		} catch (TaskCancelledException e) {
			fireCancelEvent();
			return;
		} finally {
			loadFromUriLock.unlock();
		}

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

这里一开始进行了一些基本的判断,比如是否当前暂停加载,延时加载等情况。

 

接下来,因为设置到了下载读写等过程,所以加了 锁,保证线程安全,下载过程是在 上面的// cache 中没有,这个注释下面的tryLoadBitmap() 方法中进行的,这个方法中做了什么,我们一会在看,现在继续往下走,下载后拿到了bitmap,接着进行判断是否 把bitmap加入到内存中的缓存中。 最后在DisplayBitmapTask 的run 方法中setImageBitmap设置为背景。

 

这就是大体工作流程,也是前面说的的 三种情况

1. 内存中有,直接显示。

2. 内存中没有 本地有,加载进内存并显示。

3 本地没有,网络下载,本地保存,加载进内存,显示。

 

接下来再看前面说的下载方法tryLoadBitmap(), 由于比较长,这里只看关键的 try代码块中的操作:

 

		// 尝试 本地文件中是否有缓存
			File imageFile = configuration.diskCache.get(uri);
			if (imageFile != null && imageFile.exists() && imageFile.length() > 0) {
				L.d(LOG_LOAD_IMAGE_FROM_DISK_CACHE, memor



 
分享到:QQ空间新浪微博腾讯微博微信百度贴吧QQ好友复制网址打印

您可能想查找下面的文章:

  • Android-Universal-Image-Loader (图片异步加载缓存库)的源码解读

相关文章

  • 2017-05-26高通QCOM 8610平台电量计算
  • 2017-05-26基于docker安装gitlab
  • 2017-05-26向量时钟算法简介
  • 2017-05-26安卓界面基本组件------计时器,安卓------计时器
  • 2017-05-26Android Drawable的9种子类 介绍
  • 2017-05-26msm8909+android5.1.1 由BLSP3改为BLSP1后SPI读写速度慢问题解决
  • 2017-05-26仿微信底部TAG完美渐变,tag渐变
  • 2017-07-22Android深入四大组件(四)广播的注册、发送和接收过程
  • 2017-05-26从编程的角度理解gradle脚本??Android Studio脚本构建和编程
  • 2017-05-26使用Chrome远程调试GenyMotion上的WebView程序,genymotionwebview

文章分类

  • JavaScript
  • ASP.NET
  • PHP
  • 正则表达式
  • AJAX
  • JSP
  • ASP
  • Flex
  • XML
  • 编程技巧
  • Android
  • swift
  • C#教程
  • vb
  • vb.net
  • C语言
  • Java
  • Delphi
  • 易语言
  • vc/mfc
  • 嵌入式开发
  • 游戏开发
  • ios
  • 编程问答
  • 汇编语言
  • 微信小程序
  • 数据结构
  • OpenGL
  • 架构设计
  • qt
  • 微信公众号

最近更新的内容

    • 找不到draw9patch.bat?已经不用找了,draw9patch.bat
    • Android版本和API Level对应关系,androidlevel
    • Android 应用程序集成Google 登录,androidgoogle
    • Android Studio发布到Jcenter
    • Android四大组件之BroadcastReceiver
    • Android消息机制
    • 4.4.2 ContentProvider再探——Document Provider
    • Android中使用Notification实现普通通知栏(Notification示例一),rest示例java实现
    • Kotlin的数据类:节省很多行代码(KAD 10),kotlin很多行
    • 记一次Android系统下解决音频UnderRun问题的过程

关于我们 - 联系我们 - 免责声明 - 网站地图

©2020-2025 All Rights Reserved. linkedu.com 版权所有