android 加载图片oom若干方案小结

简介: 本文根据网上提供的一些技术方案加上自己实际开发中遇到的情况小结。 众所周知,每个Android应用程序在运行时都有一定的内存限制,限制大小一般为16MB或24MB(视手机而定)。一般我们可以通过获取当前线程的可运行内存来判断,比如系统分给当前运行内存只有16M,而你的图片就有16M,这肯定会oom的。 相关知识介绍 1.颜色模型 常见的颜色模型有RGB、YUV、

本文根据网上提供的一些技术方案加上自己实际开发中遇到的情况小结。

众所周知,每个Android应用程序在运行时都有一定的内存限制,限制大小一般为16MB或24MB(视手机而定)。一般我们可以通过获取当前线程的可运行内存来判断,比如系统分给当前运行内存只有16M,而你的图片就有16M,这肯定会oom的。

相关知识介绍

1.颜色模型

常见的颜色模型有RGB、YUV、CMYK等,在大多数图像API中采用的都是RGB模型,Android也是如此;另外,在Android中还有包含透明度Alpha的颜色模型,即ARGB。

2.计算机中颜色值的数字化编码

(1)浮点数编码:比如float: (1.0, 0.5, 0.75),每个颜色分量各占1个float字段,其中1.0表示该分量的值为全红或全绿或全蓝;

(2)24位的整数编码:比如24-bit:(255, 128, 196),每个颜色分量各占8位,取值范围0-255,其中255表示该分量的值为全红或全绿或全蓝;

(3)16位的整数编码:比如16-bit:(31, 45, 31),第1和第3个颜色分量各占5位,取值范围0-31,第2个颜色分量占6位,取值范围0-63;

3.Bitmap在内存中的存储区域

http://www.7dot9.com/2010/08/android-bitmap%E5%86%85%E5%AD%98%E9%99%90%E5%88%B6/一文中对Android内存限制问题做了一些探讨,作者认为Bitmap对象通过栈上的引用来指向堆上的Bitmap对象,而Bitmap对象又对应了一个使用了外部存储的native图像,实际上使用的是byte[]来存储的内存空间。但为了确保外部分配内存成功,应该保证当前已分配的内存加上当前需要分配的内存值,大小不能超过当前堆的最大内存值,而且内存管理上将外部内存完全当成了当前堆的一部分。

4.Java对象的引用类型

(1)强引用(StrongReference)如果一个对象具有强引用,那垃圾回收器绝不会回收它。当内存空间不足,Java虚拟机宁愿抛出OutOfMemoryError错误,使程序异常终止,也不会靠随意回收具有强引用的对象来解决内存不足的问题。

(2)软引用(SoftReference)如果一个对象只具有软引用,则内存空间足够,垃圾回收器就不会回收它;如果内存空间不足了,就会回收这些对象的内存。只要垃圾回收器没有回收它,该对象就可以被程序使用。

(3)弱引用(WeakReference)弱引用与软引用的区别在于:只具有弱引用的对象拥有更短暂的生命周期。在垃圾回收器线程扫描它所管辖的内存区域的过程中,一旦发现了只具有弱引用的对象,不管当前内存空间足够与否,都会回收它的内存。

(4)虚引用(PhantomReference)“虚引用”顾名思义,就是形同虚设,与其他几种引用都不同,虚引用并不会决定对象的生命周期。如果一个对象仅持有虚引用,那么它就和没有任何引用一样,在任何时候都可能被垃圾回收器回收。

有了上面的基础储备,我们来谈谈图片的oom解决方案:

(1)缓存图像到内存,采用软引用缓存到内存,而不是在每次使用的时候都从新加载到内存;

(2)调整图像大小,手机屏幕尺寸有限,分配给图像的显示区域本身就更小,有时图像大小可以做适当调整;

(3)采用低内存占用量的编码方式,比如Bitmap.Config.ARGB_4444比Bitmap.Config.ARGB_8888更省内存;

(4)及时回收图像,如果引用了大量Bitmap对象,而应用又不需要同时显示所有图片,可以将暂时用不到的Bitmap对象及时回收掉;

(5)自定义堆内存分配大小,优化Dalvik虚拟机的堆内存分配;(这里可以参照一些第三方的图片缓存框架)

场景演示

为了说明出现OOM的场景和解决OOM的方法,我们选取了两款不同的机型来做比较:

(1)该应用展示一个gallery,该gallery只加载图片,gallery的adapter中传入图片的路径而不是图片对象本身,adapter动态加载图片;

(2)演示所用的图片预存储到sdcard的cache目录下,文件名分别为a.jpg,b.jpg…r.jpg,总共18张;

(3)图片为规格1920*1200的jpg图片,文件大小在423KB-1.48MB范围内;

(4)运行环境:模拟器——android2.2版本系统——480*320屏幕尺寸;Moto Defy——2.3.4版本CM7系统——854*480屏幕尺寸;

1.演示一

首先采用最简单的图片加载方式,不带任何图片缓存、调整大小或者回收,SimpleImageLoader.class便是承担此职责。加载图片部分的代码如下:

@Override

public Bitmap loadBitmapImage(String path) {

return BitmapFactory.decodeFile(path);

}

@Override

public Drawable loadDrawableImage(String path) {

return new BitmapDrawable(path);

}

演示结果:在模拟器上图片只能加载1-3张,之后便会出现OOM错误;在Defy上不会出现错误;原因是两者内存限制不同,Defy上运行的是第三方ROM,内存分配有40MB。另外gallery每次显示一张图片时,都要重新解析获得一张图片,尽管在Defy上还未曾出错,但当图片量加大,GC回收不及时时,还是有可能出现OOM。

2.演示二

为图片加载的添加一个软引用缓存,每次图片从缓存中获取图片对象,若缓存中不存在,才会从Sdcard加载图片,并将该对象加入缓存。同时软引用的对象也有助于GC在内存不足的时候回收它们。常见的Discache就是这个原理,大家有兴趣的可以自行研究。关键代码

private HashMap> mImageCache;

@Override

public Bitmap loadBitmapImage(String path) {

if(mImageCache.containsKey(path)) {

SoftReferencesoftReference = mImageCache.get(path);

Bitmap bitmap = softReference.get();

if(null != bitmap)

return bitmap;

}

Bitmap bitmap = BitmapFactory.decodeFile(path);

mImageCache.put(path, new SoftReference(bitmap));

return bitmap;

}

@Override

public Drawable loadDrawableImage(String path) {

return new BitmapDrawable(loadBitmapImage(path));

}

3.演示三

为了进一步避免OOM,除了缓存,还可以对图片进行压缩,进一步节省内存,多数情况下调整图片大小并不会影响应用的表现力。这个也是我之前必定做的,就是对图片进行压缩。

BitmapFactory.Options options = new BitmapFactory.Options();

options.inJustDecodeBounds = true;//如果该 值设为true那么将不返回实际的bitmap,也不给其分配内存空间,这样就避免内存溢出.

BitmapFactory.decodeFile(path, options);

可以对图片按尺寸压缩,也是不错的方案:

options.inSampleSize = Util.computeSampleSize(options, 600, (int) (1 * 1024 * 1024));

options.inJustDecodeBounds = false;

options.inDither = false;

options.inPreferredConfig = Bitmap.Config.ARGB_8888;

Bitmap bitmap = BitmapFactory.decodeFile(path, options);

4.演示四

在有些情况下,严重缩小图片还是会影响应用的显示效果的,所以有必要在尽可能少地缩小图片的前提下展示图片,手动去回收图片就变得尤为重要。所以这也是一些第三方图片库管理的时候必定用到lrucache算法的原因。

blog.csdn.net/guolin_blog/article/details/34093441

_blog/article/details/34093441
目录
相关文章
|
3月前
|
Java Android开发
Android面试题经典之Glide取消加载以及线程池优化
Glide通过生命周期管理在`onStop`时暂停请求,`onDestroy`时取消请求,减少资源浪费。在`EngineJob`和`DecodeJob`中使用`cancel`方法标记任务并中断数据获取。当网络请求被取消时,`HttpUrlFetcher`的`cancel`方法设置标志,之后的数据获取会返回`null`,中断加载流程。Glide还使用定制的线程池,如AnimationExecutor、diskCacheExecutor、sourceExecutor和newUnlimitedSourceExecutor,其中某些禁止网络访问,并根据CPU核心数动态调整线程数。
94 2
|
23天前
|
存储 缓存 编解码
Android经典面试题之图片Bitmap怎么做优化
本文介绍了图片相关的内存优化方法,包括分辨率适配、图片压缩与缓存。文中详细讲解了如何根据不同分辨率放置图片资源,避免图片拉伸变形;并通过示例代码展示了使用`BitmapFactory.Options`进行图片压缩的具体步骤。此外,还介绍了Glide等第三方库如何利用LRU算法实现高效图片缓存。
43 20
Android经典面试题之图片Bitmap怎么做优化
|
21天前
|
开发框架 Dart 前端开发
Android 跨平台方案对比之Flutter 和 React Native
本文对比了 Flutter 和 React Native 这两个跨平台移动应用开发框架。Flutter 使用 Dart 语言,提供接近原生的性能和丰富的组件库;React Native 则基于 JavaScript,具备庞大的社区支持和灵活性。两者各有优势,选择时需考虑团队技能和项目需求。
117 8
|
1月前
|
Web App开发 网络协议 Android开发
Android平台一对一音视频通话方案大比拼:WebRTC VS RTMP VS RTSP,谁才是王者?
【9月更文挑战第4天】本文详细对比了在Android平台上实现一对一音视频通话时常用的WebRTC、RTMP及RTSP三种技术方案。从技术原理、性能表现与开发难度等方面进行了深入分析,并提供了示例代码。WebRTC适合追求低延迟和高质量的场景,但开发成本较高;RTMP和RTSP则在简化开发流程的同时仍能保持较好的传输效果,适用于不同需求的应用场景。
67 1
|
2月前
|
存储 安全 API
Android经典实战之存储方案对比:SharedPreferences vs MMKV vs DataStore
本文介绍了 Android 开发中常用的键值对存储方案,包括 SharedPreferences、MMKV 和 DataStore,并对比了它们在性能、并发处理、易用性和稳定性上的特点。通过实际代码示例,帮助开发者根据项目需求选择最适合的存储方案,提升应用性能和用户体验。
49 1
|
2月前
|
Android开发 C++ 开发者
Android经典实战之跨平台开发方案:Kotlin Multiplatform vs Flutter
本文对比了Kotlin Multiplatform与Flutter两大跨平台开发框架,从技术特性、性能、开发效率、UI体验、可扩展性及适用场景等维度进行了详尽分析,帮助开发者根据项目需求和技术背景选择最优方案。
61 2
|
2月前
|
数据处理 开发工具 数据安全/隐私保护
Android平台RTMP推送|轻量级RTSP服务|GB28181接入之文字、png图片水印的精进之路
本文探讨了Android平台上推流模块中添加文字与PNG水印的技术演进。自2015年起,为了满足应急指挥及安防领域的需求,逐步发展出三代水印技术:第一代为静态文字与图像水印;第二代实现了动态更新水印内容的能力,例如实时位置与时间信息;至第三代,则优化了数据传输效率,直接使用Bitmap对象传递水印数据至JNI层,减少了内存拷贝次数。这些迭代不仅提升了用户体验和技术效率,也体现了开发者追求极致与不断创新的精神。
|
2月前
|
自然语言处理 定位技术 API
Android经典实战之如何获取图片的经纬度以及如何根据经纬度获取对应的地点名称
本文介绍如何在Android中从图片提取地理位置信息并转换为地址。首先利用`ExifInterface`获取图片内的经纬度,然后通过`Geocoder`将经纬度转为地址。注意操作需在子线程进行且考虑多语言支持。
145 4
|
2月前
|
存储 缓存 Java
Android项目架构设计问题之优化业务接口数据的加载效率如何解决
Android项目架构设计问题之优化业务接口数据的加载效率如何解决
35 0
|
2月前
|
Java Android开发 Kotlin
Android项目架构设计问题之要在Glide库中加载网络图片到ImageView如何解决
Android项目架构设计问题之要在Glide库中加载网络图片到ImageView如何解决
26 0