• 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 (图片异步加载缓存库)对Bitmap的优化处理

Android-Universal-Image-Loader (图片异步加载缓存库)对Bitmap的优化处理

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

网友通过本文主要向大家介绍了Android-Universal-Image-Loader (图片异步加载缓存库)对Bitmap的优化处理等相关知识,希望对您有所帮助,也希望大家支持linkedu.com www.linkedu.com

Android-Universal-Image-Loader (图片异步加载缓存库)对Bitmap的优化处理


前言:

前面两篇分别介绍了:

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

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

通过前两篇,我们了解了 UIL的使用配置,UIL将服务器上的一张图片保存到本地,加载到内存的过程,以及UIL对DiscCache和MemoryCache的策略,但是还有一部分比较重要,因为它是我们的开发日常中经常要处理的一个问题:Bitmap的优化。换句话说:如何将一个大的图片,加载到内存并显示,如果我们不处理,那么很容易发生OOM。

那么UIL作为一款经典图片缓存框架接下来,我们就学习一下UIL中如何优化Bitmap,避免发生OOM的,以后在我们项目开发的时候就可以用相同的方法去解决类似的问题。

正文

大图片加载到内存的两种方法对比

首先我们先不用UIL ,直接加载一张大图片会发生什么?

\

将上述21M的本地图片aaa.jpg直接通过加载到内存

 

private String uri_virtual="/mnt/sdcard/UIL/Document/pics/aaa.jpg";
Bitmap bm=BitmapFactory.decodeFile(uri_virtual);
errImage.setImageBitmap(bm);
运行一下程序会发现发生了crash

 

\
在logcat中报错如下

\

这是一个非常常见的错误:内存溢出(Out Of Memory)。

导致这个错误的原因一般是 加载了一个超过dalivk heap 的size(一般16M) 的文件,或者 内存使用频繁,释放不及时,导致内存不够用。

解决OOM的方法就是: 使用弱引用WeakReference,手动释放内存System.gc(),将Bitmap压缩 等。

那么我们在用UIL去加载这一张大图片:

 

		image = (ImageView) findViewById(R.id.iv);
		DisplayImageOptions displayOptions = new DisplayImageOptions.Builder()
				.cacheInMemory(true).bitmapConfig(Bitmap.Config.RGB_565)
				.cacheOnDisk(true).build();
		ImageLoader.getInstance().displayImage(uri_virtual, image,
				displayOptions);
发现加载成功:

 

\
可见UIL 内部对其进行了处理,使其加载成功。

UIL加载优化分析

加载的过程 上一篇已经分析过了,这里我们直接从LoadAndDisplayImageTask的run() 方法入手,因为在run() 方法里 将本地文件 转成inputStream。</div> 在run() 方法里面找到这样一个方法tryLoadBitmap(),在其方法内有这样一段代码:</div>
	// 尝试 本地文件中是否有缓存
	File imageFile = configuration.diskCache.get(uri);
	if (imageFile != null && imageFile.exists() && imageFile.length() > 0) {
		L.d(LOG_LOAD_IMAGE_FROM_DISK_CACHE, memoryCacheKey);
		loadedFrom = LoadedFrom.DISC_CACHE;
		checkTaskNotActual();
		bitmap = decodeImage(Scheme.FILE.wrap(imageFile.getAbsolutePath()));
	}
</div> 这里07行,执行了一个decodeImage 的方法,根据返回值 跟传入的参数,我们不难看出,这个方法的作用是,根据本地图片的路径,将其转成bitmap加载进内存。</div>
	private Bitmap decodeImage(String imageUri) throws IOException {
		ViewScaleType viewScaleType = imageAware.getScaleType();
		ImageDecodingInfo decodingInfo = new ImageDecodingInfo(memoryCacheKey, imageUri, uri, targetSize, viewScaleType,
				getDownloader(), options);
		return decoder.decode(decodingInfo);
	}
</div> 从上面的 decodeImage 方法的实现来看,最终 将本地文件转成bitmap 是由decoder.decode(decodingInfo) 来完成的。那么就去看decode() 方法:</div> ImageDecoder 是一个接口,BaseImageDecoder实现了ImageDecoder ,实现了decode 方法:</div>
	/**
	 * Decodes image from URI into {@link Bitmap}. Image is scaled close to incoming {@linkplain ImageSize target size}
	 * during decoding (depend on incoming parameters).
	 * @param decodingInfo Needed data for decoding image: 如果 具体View  没有指定 wh  为手机分辨率 px 否则为 设置的px值
	 * @return Decoded bitmap
	 * @throws IOException                   if some I/O exception occurs during image reading
	 * @throws UnsupportedOperationException if image URI has unsupported scheme(protocol)
	 */
	@Override
	public Bitmap decode(ImageDecodingInfo decodingInfo) throws IOException {
		Bitmap decodedBitmap;
		ImageFileInfo imageInfo;
		InputStream imageStream = getImageStream(decodingInfo);
		if (imageStream == null) {
			L.e(ERROR_NO_IMAGE_STREAM, decodingInfo.getImageKey());
			return null;
		}
		try {
			imageInfo = defineImageSizeAndRotation(imageStream, decodingInfo);
			imageStream = resetStream(imageStream, decodingInfo);
			Options decodingOptions = prepareDecodingOptions(imageInfo.imageSize, decodingInfo);
			decodedBitmap = BitmapFactory.decodeStream(imageStream, null, decodingOptions);
		} finally {
			IoUtils.closeSilently(imageStream);
		}
		if (decodedBitmap == null) {
			L.e(ERROR_CANT_DECODE_IMAGE, decodingInfo.getImageKey());
		} else {
			decodedBitmap = considerExactScaleAndOrientatiton(decodedBitmap, decodingInfo, imageInfo.exif.rotation,
					imageInfo.exif.flipHorizontal);
		}
		return decodedBitmap;
	}
再看方法以前,我先解释一下ImageDecodingInfo 这是一个非常重要的类,它里面封装了我们布局里设置子的ImageView的一些属性,比如 android:layout_width android:layout_height</div> 以及一些Options 属性。</div>

Options 属性介绍

destOptions.inDensity 
destOptions.inDither 
destOptions.inInputShareable 
destOptions.inJustDecodeBounds 
destOptions.inPreferredConfig 
destOptions.inPurgeable
destOptions.inSampleSize 
destOptions.inScaled
destOptions.inScreenDensity
destOptions.inTargetDensity 
destOptions.inTempStorage 
destOptions.inPreferQualityOverSpeed
destOptions.inBitmap
destOptions.inMutable 
</div> 而对Bitmap的压缩,都是按照bitmap的这些属性来做的。</div> 介绍完了ImageDecodingInfo ,我们接着回到上面的decode() 方法,我们看到13行 拿到了InputStream 接下来 在19行,根据InputSream 拿到了本地图片的分辨率信息,一起看一下defineImageSizeAndRotation() 方法:</div>

根据InpuStream 使用Options.inJustDecodeBounds获取图片信息

	/**
	 * //options.outWidth:11935options.outHeight:8554  根据文件流 拿到 本地图片的分辨率
	 * @param imageStream: 文件流
	 * @param decodingInfo: 本地图片的文件信息
	 * @return
	 * @throws IOException
	 */
	protected ImageFileInfo defineImageSizeAndRotation(InputStream imageStream, ImageDecodingInfo decodingInfo)
			throws IOException {
		Options options = new Options();
		options.inJustDecodeBounds = true;
		BitmapFactory.decodeStream(imageStream, null, options);
		ExifInfo exif;
		String imageUri = decodingInfo.getImageUri();
		if (decodingInfo.shouldConsiderExifParams() && canDefineExifParams(imageUri, options.outMimeType)) {
			exif = defineExifOrientation(imageUri);
		} else {
			exif = new ExifInfo();
		}
		//options.outWidth:11935options.outHeight:8554  根据文件流 拿到 本地图片的分辨率
		return new ImageFileInfo(new ImageSize(options.outWidth, options.outHeight, exif.rotation), exif);
	}
</div> 关键是 10 11 12 这三行,首先设置Options.inJustDecodeBounds=true 这样设置</div> 意思就是:</div> 如果设置为真,解码器将返回空(无位图),但输出…字段将设置为,允许调用方查询该位图而不必为其像素分配内存。</div> 在接下来12行执行时,将只会获取到分辨率的大小,而不会将bitmap 加载到内存。</div> 拿到了大小,这个方法就是将本地图片的信息封装一下,然后返回,我们在回到decode() 方法,经过20 21 22 这三行,我们就拿到了最终符合我们需要的bitmap,那么一起看这三行做的事情:</div> imageStream = resetStream(imageStream, decodingInfo); //重新获取一次文件流</div> 最关键的是22行 经过prepareDecodingOptions() 拿到了最终的Options:</div>

根据本地图片属性与布局中的ImagView 比较,算出缩放比例:

       /**
	 * @param imageSize 本地图片的大小
	 * 



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

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

相关文章

  • 2017-05-26Android种使用Notification实现通知管理以及自定义通知栏(Notification示例四),自定义notification
  • 2017-05-26Android--数据库数据显示至屏幕
  • 2017-05-26Android开发技巧之Camera拍照功能
  • 2017-05-26Android5.0开发范例大全 读书笔记(五),android5.0范例
  • 2017-05-26Touch事件分发
  • 2017-05-26GridView嵌套在ScrollView里只有一行的问题,gridviewscrollview
  • 2017-05-26安卓高级组件-----图像切换器,安卓-----切换器
  • 2017-05-227.1.3 Android HTTP请求方式:HttpURLConnection
  • 2017-05-26精品干货丨APP常用导航框架,干货丨app导航
  • 2017-05-26安卓界面基本组件------计时器,安卓------计时器

文章分类

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

最近更新的内容

    • Android中的 init.rc文件简介,androidinit.rc
    • onTouch和onTouchEvent,ontouch
    • linux文件系统的规模与瓶颈
    • android studio 使用checkstyle全攻略
    • 我的android学习经历15,android学习经历15
    • Android 应用程序集成Google 登录,androidgoogle
    • 找不到draw9patch.bat?已经不用找了,draw9patch.bat
    • android fragment生命周期应用
    • 报错:You need to use a Theme.AppCompat theme (or descendant) with this activity.,theme.appcompat报错
    • 在Android studio中进行单元测试和ui测试的分析

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

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