码迷,mamicode.com
首页 > 移动开发 > 详细

Android--Bitmap性能优化

时间:2015-10-24 00:18:46      阅读:389      评论:0      收藏:0      [点我收藏+]

标签:

今天做项目,发现需要显示一张超大图片,处理过后,还有561Kb

     加载的时候,就crash --- OOM

     shortMsg:java.lang.OutOfMemoryError

     longMsg:java.lang.OutOfMemoryError: bitmap size exceeds VM budget

     stackTrace:java.lang.OutOfMemoryError: bitmap size exceeds VM budget
     at android.graphics.Bitmap.nativeCreate(Native Method)
     at android.graphics.Bitmap.createBitmap(Bitmap.java:477)
     at android.graphics.Bitmap.createBitmap(Bitmap.java:444)
     at android.graphics.Bitmap.createScaledBitmap(Bitmap.java:349)
     at android.graphics.BitmapFactory.finishDecode(BitmapFactory.java:512)
     at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:487)
     at android.graphics.BitmapFactory.decodeResourceStream(BitmapFactory.java:336)

     

      代码如下:

  //this line will lead to OOM 

      detailView=(ImageView)findViewById(R.id.detailView);

      detailView.setBackgroundResource(R.drawable.more_info);

 

       换成这种:

      detailView.setImageResource(R.drawable.more_info); //也同样会OOM

 

       

       后来找到了solution:

    /**
     * 以最省内存的方式读取本地资源的图片
     * @param context
     *@param resId
     * @return
     */
    public static Bitmap readBitMap(Context context, int resId){
        BitmapFactory.Options opt = new BitmapFactory.Options();
        opt.inPreferredConfig = Bitmap.Config.RGB_565;
        opt.inPurgeable = true;
        opt.inInputShareable = true;
        //获取资源图片
        InputStream is = context.getResources().openRawResource(resId);
        return BitmapFactory.decodeStream(is,null,opt);
    }

 

    取得bitmap之后,再 detailView.setImageBitmap(pdfImage); 就ok了!      

 

   那是为什么,会导致oom呢:

         原来当使用像

    imageView.setBackgroundResource,

    imageView.setImageResource,

    BitmapFactory.decodeResource  这样的方法来设置一张大图片的时候

         这些函数在完成decode后,最终都是通过java层的createBitmap来完成的,需要消耗更多内存。

         因此,

    1、改用先通过BitmapFactory.decodeStream方法,创建出一个bitmap

    2、再将其设为ImageView的 source,decodeStream最大的秘密在于其直接调用JNI>>nativeDecodeAsset()来完成decode,无需再使用java层的createBitmap,从而节省了java层的空间。

  如果在读取时加上图片Config参数,可以跟有效减少加载的内存,从而跟有效阻止抛out of Memory异常。

        另外,需要特别注意: 

    decodeStream是直接读取图片资料的字节码的, 不会根据机器的各种分辨率来自动适应,使用了decodeStream之后,需要在hdpi和mdpi,ldpi中配置相应的图片资源,否则在不同分辨率机器上都是同样大小(像素点数量),显示出来的大小就不对了。

 


在加载图片资源时,可采用以下一些方法来避免OOM的问题: 
1,在Android 2.3.3以及之前,建议使用Bitmap.recycle()方法,及时释放资源。 

 

1,在Android 3.0开始

可设置BitmapFactory.options.inBitmap值,(从缓存中获取)达到重用Bitmap的目的。如果设置,则inPreferredConfig属性值会被重用的Bitmap该属性值覆盖。 

2,通过设置Options.inPreferredConfig值来降低内存消耗: 
     ARGB_8888: 每个像素4字节. 共32位。   它为默认值
     Alpha_8: 只保存透明度,共8位,1字节。 
     ARGB_4444: 共16位,2字节。 
     RGB_565:共16位,2字节。 
     如果不需要透明度,可把默认值ARGB_8888改为RGB_565,节约一半内存。 
3,通过设置Options.inSampleSize 对大图片进行压缩,可先设置Options.inJustDecodeBounds,获取Bitmap的外围数据,宽和高等。然后计算压缩比例,进行压缩。 
4,设置Options.inPurgeableinInputShareable:让系统能及时回收内存。 
       1、inPurgeable:

    (1)设置为True,则使用BitmapFactory创建的Bitmap用于存储Pixel的内存空间,在系统内存不足时可以被回收,当应用需要再次访问该Bitmap的Pixel时,系统会再次调用BitmapFactory 的decode方法重新生成Bitmap的Pixel数组。 
     (2)设置为False时,表示不能被回收。 

   2、inInputShareable:设置是否深拷贝,与inPurgeable结合使用,inPurgeable为false时,该参数无意义。 
                                  True:  share  a reference to the input data(inputStream, array,etc)

              False :a deep copy
5,使用decodeStream代替其他decodeResource,setImageResource,setImageBitmap等方法来加载图片。 
     区别: 
      (1)decodeStream直接读取图片字节码,调用nativeDecodeAsset/nativeDecodeStream来完成decode。无需使用Java空间的一些额外处理过程,节省dalvik内存。但是由于直接读取字节码,没有处理过程,因此不会根据机器的各种分辨率来自动适应,需要在hdpi,mdpi和ldpi中分别配置相应的图片资源,否则在不同分辨率机器上都是同样的大小(像素点数量),显示的实际大小不对。 
      decodeResource会在读取完图片数据后,根据机器的分辨率,进行图片的适配处理,导致增大了很多dalvik内存消耗。 

       decodeStream调用过程: decodeStream(InputStream,Rect,Options) -> nativeDecodeAsset/nativeDecodeStream 
       decodeResource调用过程:即finishDecode之后,调用额外的Java层的createBitmap方法,消耗更多dalvik内存。 
             decodeResource(Resource,resId,Options)  -> decodeResourceStream (设置Options的inDensity和inTargetDensity参数)  -> decodeStream() (在完成Decode后,进行finishDecode操作) 
             finishDecode() -> Bitmap.createScaleBitmap()(根据inDensity和inTargetDensity计算scale) -> Bitmap.createBitmap() 

以上方法的组合使用,合理避免OOM错误。 
                    

 

Android--Bitmap性能优化

标签:

原文地址:http://www.cnblogs.com/zrui513/p/4905895.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!