在编写Android程序的时候,我们总是难免会碰到OOM(OUT OF MEMORY)的错误,那

在编写Android程序的时候,我们总是难免会碰到OOM(OUT OF MEMORY)的错误,那

么这个错误究竟是怎么来的呢,可以先看一下这篇文章 ANDROID BITMAP 内存限制

OOM,OUT OF MEMORY。 

 

这里,我使用 Gallery 来举例,在模拟器中,不会出现 OOM 错误,但是,一旦把程序运

行到真机里,图片文件一多,必然会出现OOM,我们通过做一些额外的处理来避免。 

 

1.创建一个图片缓存对象HashMap dataCache,integer对应Adapter中的位置position,我

们只用缓存处在显示中的图片,对于之外的位置,如果  dataCache 中有对应的图片,我

们需要进行回收内存。在这个例子中,Adapter 对象的 getView 方法首先判断该位置是否

有缓存的  bitmap,如果没有,则解码图片(bitmapDecoder.getPhotoItem,BitmapDecoder

类见后面)并返回 bitmap  对象,设置 dataCache  在该位置上的 bitmap 缓存以便之后使

用;若是该位置存在缓存,则直接取出来使用,避免了再一次调用底层的解码图像需要

的内存开销。有时为了提高  Gallery的更新速度,我们还可以预存储一些位置上的bitmap,

比如存储显示区域位置外向上3个向下 3个位置的bitmap,这样上或下滚动  Gallery时可

以加快getView的获取。

 

 

Java代码 复制代码  收藏代码
  1. public View getView(int position, View convertView, ViewGroup parent)    
  2. {    
  3.           
  4.                                 
  5.           
  6.                              if(convertView==null){    
  7.           
  8.                                      LayoutInflater inflater  =    
  9.   
  10. LayoutInflater.from(context);    
  11.           
  12.                                      convertView =    
  13. inflater.inflate(R.layout.photo_item, null);    
  14.           
  15.     
  16.           
  17.                          holder = new ViewHolder();    
  18.           
  19.                          holder.photo = (ImageView)    
  20. convertView.findViewById(R.id.photo_item_image);    
  21.           
  22.                          holder.photoTitle = (TextView)    
  23. convertView.findViewById(R.id.photo_item_title);    
  24.           
  25.                          holder.photoDate = (TextView)    
  26. convertView.findViewById(R.id.photo_item_date);    
  27.           
  28.                          convertView.setTag(holder);    
  29.           
  30.                              }else {    
  31.           
  32.                              holder = (ViewHolder)    
  33. convertView.getTag();    
  34.           
  35.                          }    
  36.           
  37.                              cursor.moveToPosition(position);    
  38.           
  39.                                 
  40.           
  41.                              Bitmap current =    
  42. dateCache.get(position);    
  43.           
  44.                              if(current != null){//如果缓存中已解码   
  45. 该图片,则直接返回缓存中的图片    
  46.           
  47.                                        
  48. holder.photo.setImageBitmap(current);    
  49.           
  50.                              }else {    
  51.           
  52.                                      current =    
  53. bitmapDecoder.getPhotoItem(cursor.getString(1), 2) ;holder.photo.setImageBitmap(current);    
  54.           
  55.                                      dateCache.put(position,    
  56. current);    
  57.           
  58.                              }    
  59.           
  60.                                 
  61. holder.photoTitle.setText(cursor.getString(2));    
  62.           
  63.                                
  64. holder.photoDate.setText(cursor.getString(4));    
  65.           
  66.                              return convertView;    
  67.           
  68.                      }    
  69.           
  70.                         
  71.           
  72.              }   
public View getView(int position, View convertView, ViewGroup parent) 
{ 
       
                             
       
                             if(convertView==null){ 
       
                                     LayoutInflater inflater  = 

LayoutInflater.from(context); 
       
                                     convertView = 
inflater.inflate(R.layout.photo_item, null); 
       
 
       
                         holder = new ViewHolder(); 
       
                         holder.photo = (ImageView) 
convertView.findViewById(R.id.photo_item_image); 
       
                         holder.photoTitle = (TextView) 
convertView.findViewById(R.id.photo_item_title); 
       
                         holder.photoDate = (TextView) 
convertView.findViewById(R.id.photo_item_date); 
       
                         convertView.setTag(holder); 
       
                             }else { 
       
                             holder = (ViewHolder) 
convertView.getTag(); 
       
                         } 
       
                             cursor.moveToPosition(position); 
       
                             
       
                             Bitmap current = 
dateCache.get(position); 
       
                             if(current != null){//如果缓存中已解码
该图片,则直接返回缓存中的图片 
       
                                    
holder.photo.setImageBitmap(current); 
       
                             }else { 
       
                                     current = 
bitmapDecoder.getPhotoItem(cursor.getString(1), 2) ;holder.photo.setImageBitmap(current); 
       
                                     dateCache.put(position, 
current); 
       
                             } 
       
                             
holder.photoTitle.setText(cursor.getString(2)); 
       
                            
holder.photoDate.setText(cursor.getString(4)); 
       
                             return convertView; 
       
                     } 
       
                     
       
             } 

 

BitmapDecoder.class 

 

 

Java代码 复制代码  收藏代码
  1. package com.wuyi.bestjoy;    
  2.           
  3.     
  4.           
  5.      import java.io.FileNotFoundException;    
  6.           
  7.      import java.io.FileOutputStream;    
  8.           
  9.     
  10.           
  11.      import android.content.Context;    
  12.           
  13.      import android.graphics.Bitmap;    
  14.           
  15.      import android.graphics.BitmapFactory;    
  16.           
  17.      import android.graphics.Matrix;    
  18.           
  19.     
  20.           
  21.      public class BitmapDecoder {    
  22.           
  23.              private static final String TAG = "BitmapDecoder";   
package com.wuyi.bestjoy; 
       
 
       
     import java.io.FileNotFoundException; 
       
     import java.io.FileOutputStream; 
       
 
       
     import android.content.Context; 
       
     import android.graphics.Bitmap; 
       
     import android.graphics.BitmapFactory; 
       
     import android.graphics.Matrix; 
       
 
       
     public class BitmapDecoder { 
       
             private static final String TAG = "BitmapDecoder"; 
Java代码 复制代码  收藏代码
  1.   private Context context;    
  2.           
  3.              public BitmapDecoder(Context context) {    
  4.           
  5.                      this.context = context;    
  6.           
  7.              }    
  8.           
  9.                 
  10.           
  11.              public Bitmap getPhotoItem(String filepath,int size) {    
  12.           
  13.                    BitmapFactory.Options options = new    
  14. BitmapFactory.Options();    
  15.           
  16.                      options.inSampleSize=size;    
  17.           
  18.                      Bitmap bitmap =    
  19. BitmapFactory.decodeFile(filepath,options);    
  20.           
  21.                      bitmap=Bitmap.createScaledBitmap(bitmap, 180,    
  22. 251true);//预先缩放,避免实时缩放,可以提高更新率    
  23.           
  24.                    return bitmap;    
  25.           
  26.                        
  27.           
  28.              }    
  29.           
  30.      }  
  private Context context; 
       
             public BitmapDecoder(Context context) { 
       
                     this.context = context; 
       
             } 
       
             
       
             public Bitmap getPhotoItem(String filepath,int size) { 
       
                   BitmapFactory.Options options = new 
BitmapFactory.Options(); 
       
                     options.inSampleSize=size; 
       
                     Bitmap bitmap = 
BitmapFactory.decodeFile(filepath,options); 
       
                     bitmap=Bitmap.createScaledBitmap(bitmap, 180, 
251, true);//预先缩放,避免实时缩放,可以提高更新率 
       
                   return bitmap; 
       
                    
       
             } 
       
     }

 

 

2.由于Gallery控件的特点,总有一个item处于当前选择状态,我们利用此时进行

dataCache中额外不用的bitmap的清理,来释放内存。 

 

 

Java代码 复制代码  收藏代码
  1.  @Override    
  2.           
  3.              public void onItemSelected(AdapterView<?> parent, View    
  4. view, int position,long id) {    
  5.           
  6.                         
  7.           
  8.                      releaseBitmap();    
  9.           
  10.                      Log.v(TAG, "select id:"+ id);    
  11.          
  12.              }    
  13.           
  14.     
  15.           
  16.      private void releaseBitmap(){    
  17.           
  18.          //在这,我们分别预存储了第一个和最后一个可见位置之外的3个   
  19. 位置的bitmap    
  20.           
  21.          //即dataCache中始终只缓存了(M=6+Gallery当前可见view的个   
  22. 数)M个bitmap    
  23.           
  24.                      int start = mGallery.getFirstVisiblePosition()-3;    
  25.           
  26.                      int end = mGallery.getLastVisiblePosition()+3;    
  27.           
  28.                      Log.v(TAG, "start:"+ start);    
  29.           
  30.                      Log.v(TAG, "end:"+ end);    
  31.           
  32.                      //释放position<start之外的bitmap资源    
  33.           
  34.                      Bitmap delBitmap;    
  35.           
  36.                      for(int del=0;del<start;del++){    
  37.           
  38.                              delBitmap = dateCache.get(del);    
  39.           
  40.                              if(delBitmap != null){    
  41.           
  42.                                       //如果非空则表示有缓存的   
  43. bitmap,需要清理    
  44.           
  45.                                      Log.v(TAG, "release position:"+    
  46. del);    
  47.           
  48.                                      //从缓存中移除该del->bitmap的   
  49. 映射    
  50.           
  51.                                      dateCache.remove(del);    
  52.           
  53.                                       delBitmap.recycle();    
  54.           
  55.                              }    
  56.                      }    
  57.           
  58.     
  59.           
  60.                      freeBitmapFromIndex(end);    
  61.           
  62.                         
  63.           
  64.              }    
  65.           
  66.                 
  67.           
  68.              /**   
  69.          
  70.               * 从某一位置开始释放bitmap资源   
  71.          
  72.               * @param index   
  73.          
  74.               */    
  75.           
  76.              private void freeBitmapFromIndex(int end) {    
  77.           
  78.                      //释放之外的bitmap资源    
  79.           
  80.                      Bitmap delBitmap;    
  81.           
  82.                       for(int del =end+1;del<dateCache.size();del++){    
  83.           
  84.                              delBitmap = dateCache.get(del);    
  85.           
  86.                              if(delBitmap != null){    
  87.           
  88.                                      dateCache.remove(del);    
  89.           
  90.                                      delBitmap.recycle();    
  91.           
  92.                                      Log.v(TAG, "release position:"+    
  93. del);    
  94.           
  95.                              }    
  96.           
  97.                                 
  98.           
  99.                      }    
  100.           
  101.              }  
 @Override 
       
             public void onItemSelected(AdapterView<?> parent, View 
view, int position,long id) { 
       
                     
       
                     releaseBitmap(); 
       
                     Log.v(TAG, "select id:"+ id); 
      
             } 
       
 
       
     private void releaseBitmap(){ 
       
         //在这,我们分别预存储了第一个和最后一个可见位置之外的3个
位置的bitmap 
       
         //即dataCache中始终只缓存了(M=6+Gallery当前可见view的个
数)M个bitmap 
       
                     int start = mGallery.getFirstVisiblePosition()-3; 
       
                     int end = mGallery.getLastVisiblePosition()+3; 
       
                     Log.v(TAG, "start:"+ start); 
       
                     Log.v(TAG, "end:"+ end); 
       
                     //释放position<start之外的bitmap资源 
       
                     Bitmap delBitmap; 
       
                     for(int del=0;del<start;del++){ 
       
                             delBitmap = dateCache.get(del); 
       
                             if(delBitmap != null){ 
       
                                      //如果非空则表示有缓存的
bitmap,需要清理 
       
                                     Log.v(TAG, "release position:"+ 
del); 
       
                                     //从缓存中移除该del->bitmap的
映射 
       
                                     dateCache.remove(del); 
       
                                      delBitmap.recycle(); 
       
                             } 
                     } 
       
 
       
                     freeBitmapFromIndex(end); 
       
                     
       
             } 
       
             
       
             /** 
       
              * 从某一位置开始释放bitmap资源 
       
              * @param index 
       
              */ 
       
             private void freeBitmapFromIndex(int end) { 
       
                     //释放之外的bitmap资源 
       
                     Bitmap delBitmap; 
       
                      for(int del =end+1;del<dateCache.size();del++){ 
       
                             delBitmap = dateCache.get(del); 
       
                             if(delBitmap != null){ 
       
                                     dateCache.remove(del); 
       
                                     delBitmap.recycle(); 
       
                                     Log.v(TAG, "release position:"+ 
del); 
       
                             } 
       
                             
       
                     } 
       
             }
 

经过这些额外的操作,有效的避免了OOM的问题。 

 

内存溢出的解决办法 

 

 

在模拟器上给 gallery 放入图片的时候,出现 java.lang.OutOfMemoryError: bitmap size 

exceeds VM budget 异常,图像大小超过了RAM内存。   

 

      模拟器RAM比较小,只有8M内存,当我放入的大量的图片(每个100 多 K左右),

就出现上面的原因。由于每张图片先前是压缩的情况。放入到 Bitmap的时候,大小会变

大,导致超出RAM内存,具体解决办法如下:   

 

//解决加载图片 内存溢出的问题   

                     //Options 只保存图片尺寸大小,不保存图片到内存   

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

                 //缩放的比例,缩放是很难按准备的比例进行缩放的,其值表明缩放的倍数,

SDK中建议其值是 2的指数值,值越大会导致图片不清晰   

                 opts.inSampleSize = 4;   

                 Bitmap bmp = null;   

                 bmp = BitmapFactory.decodeResource(getResources(), 

mImageIds[position],opts);                                

 

                 ...                 

 

                //回收   

                 bmp.recycle();   

 

通过上面的方式解决了,但是这并不是最完美的解决方式。

 

优化 Dalvik虚拟机的堆内存分配

 

 

对于 Android 平台来说,其托管层使用的 Dalvik Java VM 从目前的表现来看还有很多地

方可以优化处理,比如我们在开发一些大型游戏或耗资源的应用中可能考虑手动干涉 GC

处理,使用  dalvik.system.VMRuntime 类提供的 setTargetHeapUtilization 方法可以增强

程序堆内存的处理效率。当然具体 原理我们可以参考开源工程,这里我们仅说下使用方

法:    private final static float TARGET_HEAP_UTILIZATION = 0.75f; 在程序onCreate时

就可以调用  VMRuntime.getRuntime().setTargetHeapUtilization(TARGET_HEAP_UTILIZATION); 

即可。   

 

Android 堆内存也可自己定义大小   

 

 

  对于一些 Android 项目,影响性能瓶颈的主要是 Android 自己内存管理机制问题,目

前手机厂商对 RAM 都比较吝啬,对于软件的流畅性来说 RAM 对 性能的影响十分敏感,

除了 优化 Dalvik 虚拟机的堆内存分配外,我们还可以强制定义自己软件的对内存大小,

 

我们使用Dalvik提供的  dalvik.system.VMRuntime类来设置最小堆内存为例:   

 

private final static int CWJ_HEAP_SIZE = 6* 1024* 1024 ;   

 

VMRuntime.getRuntime().setMinimumHeapSize(CWJ_HEAP_SIZE); //设置最小 heap 内

存为6MB大小。当然对于内存吃紧来说还可以通过手动干涉GC去处理   

 

 

bitmap 设置图片尺寸,避免 内存溢出  OutOfMemoryError的优化方法   

★android 中用bitmap 时很容易内存溢出,报如下错误: Java.lang.OutOfMemoryError : 

bitmap size exceeds VM budget   

 

● 主要是加上这段:   

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

                 options.inSampleSize = 2;   

 

● eg1:(通过Uri取图片)   

private ImageView preview;   

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

                     options.inSampleSize = 2;//图片宽高都为原来的二分之一,即图片为原来

的四分之一   

                     Bitmap bitmap = BitmapFactory.decodeStream(cr   

                             .openInputStream(uri), null, options);   

                     preview.setImageBitmap(bitmap);   

以上代码可以优化内存溢出,但它只是改变图片大小,并不能彻底解决内存溢出。   

● eg2:(通过路径去图片)   

private ImageView preview;   

private String fileName= "/sdcard/DCIM/Camera/2010-05-14 16.01.44.jpg";   

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

                 options.inSampleSize = 2;//图片宽高都为原来的二分之一,即图片为原来的

四分之一   

                         Bitmap b = BitmapFactory.decodeFile(fileName, options);   

                         preview.setImageBitmap(b);   

                         filePath.setText(fileName);   

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值