8.  用缓存避免内存泄漏

很常见的一个例子就是图片的三级缓存结构,分别为网络缓存,本地缓存以及内存缓存。在内存缓存逻辑类中,通常会定义这样的集合类。

[java] view plaincopy 
  1. private HashMap<String, Bitmap> mMemoryCache = new HashMap<String, Bitmap>();//String类为该图片对应url

三级缓存结构过程介绍:

在用户切换到展示图片的界面时,当然是优先判断内存缓存是否为Null,不为空直接展示图片,若为空,同样的逻辑去判断本地缓存(不为空便设置内存缓存并展示图片),本地缓存再为空才会根据该图片的url用网络下载类去下载该图片并展示图片(当然了,下载到图片后会有设置本地缓存以及内存缓存的操作)。

内存泄漏的问题就出现在内存缓存中:只要HashMap对象实例被引用,而Bitmap对象又都是强引用,Bitmap中图片越来越多,即便是内存溢出了,垃圾回收器也不会处理。

解决方案:

(1)我们可以选择使用软引用,从而在内存不足时,垃圾回收器更容易回收Bitmap垃圾。

[java] view plaincopy 
  1. private HashMap<String, SoftReference<Bitmap>> mMemoryCache = new HashMap<String, SoftReference<Bitmap>>();

(2)Android2.3以后,SoftReference不再可靠。垃圾回收期更容易回收它,不再是内存不足时才回收软引用。那么缓存机制便失去了意义。

Google官方建议使用LruCache作为缓存的集合类。其实内部封装了LinkedHashMap。内部原理是一直判断集合大小是否超出给定的最大值,超出就把最早最少使用的对象踢出集合。

[java] view plaincopy 
  1. private LruCache<String, Bitmap> mMemoryCache = new LruCache<String, Bitmap>
  2. ((int)(Runtime.getRuntime().maxMemory()/8)){
  3. //用最大内存的1/8分配给这个集合使用
  4. //让这个集合知道每个图片的大小
  5. @Override
  6. protected int sizeOf(String key, Bitmap value){
  7. int byteCount = value.getRowBytes() * value.getHeight();//计算图片大小,每行字节数*高度
  8. return byteCount;
  9. }
  10. };

9.  优化Bitmap避免内存泄漏

Android中很多控件比如ListView/GridView/ViewPaper通常都会包含很多图片,特别是快速滑动的时候可能加载大量的图片,因此对图片进行优化处理显得尤为重要。

9.1  图片质量压缩

[java] view plaincopy
  1. public static Bitmap compressImage(Bitmap bitmap){
  2. ByteArrayOutputStream baos = new ByteArrayOutputStream();
  3. //质量压缩方法,参数100表示不压缩,把压缩后的数据存放到baos中
  4. bitmap.compress(Bitmap.CompressFormat.JPEG, 100, baos);
  5. int options = 100;
  6. //循环判断如果压缩后图片大小>50kb就继续压缩
  7. while ( baos.toByteArray().length/1024 > 50) {
  8. //清空baos
  9. baos.reset();
  10. bitmap.compress(Bitmap.CompressFormat.JPEG, options, baos);
  11. options -= 10;//每次都减少10
  12. }
  13. //把压缩后的数据baos存放到ByteArrayInputStream中
  14. ByteArrayInputStream isBm = new ByteArrayInputStream(baos.toByteArray());
  15. //把ByteArrayInputStream数据生成图片
  16. Bitmap newBitmap = BitmapFactory.decodeStream(isBm, null, null);
  17. return newBitmap;
  18. }

9.2  图片尺寸裁剪

如果说没有裁剪,下载下来是200*200,而ImageView本身是100*100的,具体原因可以参考这篇文章,这样就浪费了一部分内存。

使用BitmapFactory.Options设置inSampleSize就可以缩小图片。如果该值为2,则缩略图的宽和高都是原始图片的1/2,图片的大小就为原始大小的1/4(小于等于1不缩放)。具体方法如下:

既然有了inSampleSize的概念,我们就要对比实际图片大小和ImageView控件的大小,如果使用内存直接处理实际图片的Bitmap从而得到实际大小的话,就失去了图片尺寸裁剪的意义,因为内存已经被消耗了。因此BitmapFactory.Options提供了inJustDecodeBounds标志位,当它被设置为true后,再使用decode系列方法时,并不会真正的分配内存空间,这样解码出来的Bitmap为null,但是可以计算出原始图片的真实宽高,即options.outWidth和options.outHeight。通过这两个值,就可以知道图片是否过大了。

[java] view plaincopy 
  1. BitmapFactory.Options options = new BitmapFactory.Options();
  2. options.inJustDecodeBounds = true;
  3. BitmapFactory.decodeResource(getResources(), R.id.myimage, options);
  4. int imageHeight = options.outHeight;
  5. int imageWidth = options.outWidth;
  6. String imageType = options.outMimeType;

这里提供了一个calculateInSampleSize()工具方法来帮我们根据实际情况动态计算合适的inSampleSize。

[java] view plaincopy 
  1. public static int calculateInSampleSize( //参2和3为ImageView期待的图片大小
  2. BitmapFactory.Options options, int reqWidth, int reqHeight) {
  3. // 图片的实际大小
  4. final int height = options.outHeight;
  5. final int width = options.outWidth;
  6. //默认值
  7. int inSampleSize = 1;
  8. //动态计算inSampleSize的值
  9. if (height > reqHeight || width > reqWidth) {
  10. final int halfHeight = height/2;
  11. final int halfWidth = width/2;
  12. while( (halfHeight/inSampleSize) >= reqHeight && (halfWidth/inSampleSize) >= reqWidth){
  13. inSampleSize *= 2;
  14. }
  15. }
  16. return inSampleSize;
  17. }

创建一个完整的缩略图方案:

[java] view plaincopy 
  1. public static Bitmap decodeSampledBitmapFromResource(Resources res, int resId,
  2. int reqWidth, int reqHeight) {
  3. final BitmapFactory.Options options = new BitmapFactory.Options();
  4. options.inJustDecodeBounds = true;
  5. BitmapFactory.decodeResource(res, resId, options);
  6. // 计算inSampleSize,因为前面已经设置过标志位并调用了decode方法,所以参数option包含了真实宽高信息
  7. options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
  8. // 别忘记将opts.inJustDecodeBound设置回false,否则获取的bitmap对象还是null
  9. options.inJustDecodeBounds = false;
  10. //重新加载图片
  11. return BitmapFactory.decodeResource(res, resId, options);
  12. }

当我们在使用ImageView进行设置图片资源时:

[java] view plaincopy 
  1. mImageView.setImageBitmap( //ImageView所期望的图片大小为100*100像素
  2. decodeSampledBitmapFromResource(getResources(), R.id.myimage, 100, 100));

9.3  改变图片颜色模式

Android默认的颜色格式是ARGB_8888,在不要求透明度的情况下可以改成RGB_565,这样每个像素占用的内从可从4byte将为2byte。

一张分辨率为1920x1080的图片,如果Bitmap使用ARGB_8888格式显示的话,占用的内存将是1920x1080x4个字节,将近8M内存。

10.  及时回收资源

(1)当界面不可见时我们应当将所有和界面相关的资源进行释放。

我们可以在Activity中重写onTrimMemory()方法,通过switch这个方法中的level参数,判断它是不是等于TRIM_MEMORY_UI_HIDDEN,就说明用户已经离开了我们的程序,此时就可以进行UI相关资源释放操作了,如下所示:

[java] view plaincopy 
  1. @Override
  2. public void onTrimMemory(int level) {
  3. super.onTrimMemory(level);
  4. switch (level) {
  5. case TRIM_MEMORY_UI_HIDDEN:
  6. // 进行资源释放操作
  7. break;
  8. }
  9. }

比如Android3.0开始支持的属性动画中有一类无限循环的动画,它会通过View间接持有Activity的引用,如果没有在onDestroy中停止动画(animator.cancel()),就会泄漏当前的Activity。说起动画,还有一点就是减少帧动画的使用。

(2)Google也建议在onStop()方法中释放资源,但是和上面的释放UI资源是有区别的,因为onStop()方法只是当一个Activity不可见的时候就会调用,比如说用户打开了我们程序中的另一个ActivityB。在onStop()方法中适合去关闭一些读写文件的资源、数据库操作相关的资源等等。

但是像UI相关的资源应该一直要等到onTrimMemory(TRIM_MEMORY_UI_HIDDEN)这个回调之后才去释放,否则从ActivityB回到ActivityA,UI相关的资源会重新加载。

至此关于Android内存泄漏的内容总结完毕。

本文转自 一点点征服   博客园博客,原文链接:http://www.cnblogs.com/ldq2016/p/6692174.html,如需转载请自行联系原作者

Android开发——内存优化 图片处理相关推荐

  1. android开发内存优化的那些事儿

    一.Android应用程序内存优化   在开发Android App的过程中,经常会遇到内存方面的压力,比如OOM,或者频繁GC.本文不打算涵盖内存优化的所有方面,只是介绍一下我自己遇到的问题和解决方 ...

  2. android内存优化方法,Android开发内存优化注意事项和方法

    在Android的实际开发中,可能会出现不再使用的对象无法被系统回收的情况,这种情况会导致内存泄漏,甚至内存溢出,导致程序崩溃. 检测方法:使用LeakCanary 优化方案: 1.检查使用多少内存 ...

  3. Android 系统性能优化(42)---Android代码内存优化建议-Android资源篇

    Android代码内存优化建议-Android资源篇 这篇文章主要介绍在实际Android应用程序的开发中,容易导致内存泄露的一些情况.开发人员如果在进行代码编写之前就有内存泄露方面的基础知识,那么写 ...

  4. Android 系统性能优化(41)---Android代码内存优化建议-OnTrimMemory优化

    Android代码内存优化建议-OnTrimMemory优化 OnTrimMemory 回调是 Android 4.0 之后提供的一个API,这个 API 是提供给开发者的,它的主要作用是提示开发者在 ...

  5. Android的内存优化

    腾讯公司在五月三十一日开展[腾讯Bugly移动开发人员沙龙]大会.大会上面叶方正老师解说了 关于Android的内存优化的问题,只是我感觉叶老师许多其它的站在了測试的角度上去解释了这一方面,叶老师给我 ...

  6. Rockchip Android平台内存优化及系统裁剪

    Rockchip Android平台内存优化及系统裁剪 文章目录 Rockchip Android平台内存优化及系统裁剪 编译32bit的Android系统 启用Android GO的配置 系统裁剪 ...

  7. android 多图片优化工具,总结Android App内存优化之图片优化

    前言 在Android设备内存动不动就上G的情况下,的确没有必要去太在意APP对Android系统内存的消耗,但在实际工作中我做的是教育类的小学APP,APP中的按钮.背景.动画变换基本上全是图片,在 ...

  8. Android中内存优化

    CSDN博客不写,排名会下降,我知道了...... Android内存优化,设计到很多方面,参考别大神的博客,自己也总结一下..... 下面将通过两篇博客,浅析Android 中的内存优化问题.来张图 ...

  9. Android 应用内存优化 之 onLowMemory onTrimMemory

    OnLowMemory: 是Android提供的API,在系统内存不足,所有后台程序(优先级为background的进程,不是指后台运行的进程)都被杀死时,系统会调用OnLowMemory. OnTr ...

最新文章

  1. 《编程之美》读书笔记19: 3.9 重建二叉树
  2. 通过FFT来计算螺旋线的匝数
  3. Maven+Struts2+MyBatis+Spring搭建教程
  4. vue-cli中配置sass
  5. Elasticsearch2.x Cluster Health
  6. 晒晒女儿学国画一学期的成果
  7. “写画”与“惊春”:王艾画展和当代诗人朗诵会
  8. 一个实时收集MySql变更记录的组件CanalSharp.AspNetCore
  9. python 中的数据类型
  10. 基于OMCS的远程桌面实现远程控制地面站
  11. TRUNCATE TABLE command not allowed within multi-statement transaction
  12. 【逗老师带你学IT】PRTG、Zabbix通过API监控深信服VDC和VMP云桌面运行状态
  13. 永久免费!永洪科技发布桌面智能数据分析工具Desktop,推动数据应用平民化
  14. FPGA数码管显示自动计数+按键计数+蜂鸣器
  15. Markdown使用进阶教程
  16. 分布式与微服务——Iaas,Paas和Saas、单体应用和缺点、微服务概念、传统 分布式 SOA 架构与微服务架构的区别、微服务实战、什么是RPC、CAP定理和BASE理论、唯一ID生成、实现分布式
  17. 计算机无法传送文件到打印机,发送文件给打印机却没反应?解决方案都在这里了...
  18. 对比了百度统计和CNZZ后,我最终选择了51LA
  19. 右下角弹出广告 js,漂浮效果(兼容多浏览器)
  20. LintCode 702. 连接两个字符串中的不同字符 JavaScript算法

热门文章

  1. 如何在多Node版本的情况下公用一个npm
  2. Android第三十八期 - 评价标签FlowLayout
  3. [CLR via C#]5.3 值类型的装箱和拆箱
  4. react项目部署nginx服务器
  5. 第三天-零基础学习python
  6. Python 数据类型
  7. WEB API的安全问题
  8. ARC在Release与Debug模式中内存释放的坑
  9. 混合颜料(求线性组的基)
  10. 平台数据库导入导出快捷工具说明