尽量不要使用setImageBitmap或setImageResource或BitmapFactory.decodeResource来设置一张大图,因为这些函数在完成decode后,最终都是通过java层的createBitmap来完成的,需要消耗更多内存。 

因此,改用先通过BitmapFactory.decodeStream方法,创建出一个bitmap,再将其设为ImageView的source,decodeStream最大的秘密在于其直接调用JNI>>nativeDecodeAsset()来完成decode,无需再使用java层的createBitmap,从而节省了java层的空间。

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

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


另外,以下方式也大有帮助:

1. InputStream is = this.getResources().openRawResource(R.drawable.pic1); 
  
  
   
    
   BitmapFactory.Options options=new BitmapFactory.Options(); 
  
  
   
    
   options.inJustDecodeBounds = false; 
  
  
   
    
   options.inSampleSize = 10; 
   
   //width,hight设为原来的十分一
  
  
   
    
   Bitmap btp =BitmapFactory.decodeStream(is,null,options);

2. if(!
  bmp.isRecycle() 
  ){ 
 
     
    bmp.recycle()  
 
 
        system.gc()  //提醒系统及时回收 
 
 
}

以下奉上自己写的一个方法:


    1.  
    2. public static Bitmap readBitMap(Context context, int resId){  
    3.    BitmapFactory.Options opt = new BitmapFactory.Options();  
    4.    opt.inPreferredConfig = Bitmap.Config.RGB_565;   
    5.    opt.inPurgeable = true;  
    6.    opt.inInputShareable = true;  
    7.       //获取资源图片  
    8.    InputStream is = context.getResources().openRawResource(resId);  
    9.        return BitmapFactory.decodeStream(is,null,opt);  
    10. }

    stream = new FileInputStream(new File(path+"test.jpg"));
       
       BitmapFactory.Options opts = new BitmapFactory.Options(); 
       
      
       
       Bitmap bitmap = BitmapFactory.decodeStream(stream , null, opts);


      

    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来完成的,需要消耗更多内存。

    因此,改用先通过BitmapFactory.decodeStream方法,创建出一个bitmap,再将其设为ImageView的 source,decodeStream最大的秘密在于其直接调用JNI>>nativeDecodeAsset()来完成decode,无需再使用java层的createBitmap,从而节省了java层的空间。如果在读取时加上图片的Config参数,可以跟有效减少加载的内存,从而跟有效阻止抛out of Memory异常。

    另外,需要特别注意: 

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


    BitmapFactory.decodeFile(imageFile);


    用BitmapFactory解码一张图片时,有时会遇到该错误。这往往是由于图片过大造成的。要想正常使用,则需要分配更少的内存空间来存储。

    BitmapFactory.Options.inSampleSize

    设置恰当的inSampleSize可以使BitmapFactory分配更少的空间以消除该错误。inSampleSize的具体含义请参考SDK文档。例如:

      BitmapFactory.Options opts = 
               new 
               BitmapFactory.Options(); 
              
     
               opts.inSampleSize = 
               4 
               ; 
              
     
               Bitmap bitmap = BitmapFactory.decodeFile(imageFile, opts); 
    

    如何设置恰当的inSampleSize

    设置恰当的inSampleSize是解决该问题的关键之一。BitmapFactory.Options提供了另一个成员inJustDecodeBounds。

       BitmapFactory.Options opts = 
               new 
               BitmapFactory.Options(); 
              
     
               opts.inJustDecodeBounds = 
               true 
               ; 
              
     
               Bitmap bitmap = BitmapFactory.decodeFile(imageFile, opts); 
    

    设置inJustDecodeBounds为true后,decodeFile并不分配空间,但可计算出原始图片的长度和宽度,即opts.width和opts.height。有了这两个参数,再通过一定的算法,即可得到一个恰当的inSampleSize。

    查看Android源码,Android提供了一种动态计算的方法。

     public 
               static 
               int 
               computeSampleSize(BitmapFactory.Options options, 
              
     
                        
               int 
               minSideLength, 
               int 
               maxNumOfPixels) { 
              
     
                    
               int 
               initialSize = computeInitialSampleSize(options, minSideLength, 
              
     
                            
               maxNumOfPixels); 
              
    
                  
                
              
     
                    
               int 
               roundedSize; 
              
     
                    
               if 
               (initialSize <= 
               8 
               ) { 
              
     
                        
               roundedSize = 
               1 
               ; 
              
     
                        
               while 
               (roundedSize < initialSize) { 
              
     
                            
               roundedSize <<= 
               1 
               ; 
              
     
                        
               } 
              
     
                    
               } 
               else 
               { 
              
     
                        
               roundedSize = (initialSize + 
               7 
               ) / 
               8 
               * 
               8 
               ; 
              
     
                    
               } 
              
    
                  
                
              
     
                    
               return 
               roundedSize; 
              
     
               } 
              
    
                  
                
              
     
               private 
               static 
               int 
               computeInitialSampleSize(BitmapFactory.Options options, 
              
     
                        
               int 
               minSideLength, 
               int 
               maxNumOfPixels) { 
              
     
                    
               double 
               w = options.outWidth; 
              
     
                    
               double 
               h = options.outHeight; 
              
    
                  
                
              
     
                    
               int 
               lowerBound = (maxNumOfPixels == - 
               1 
               ) ? 
               1 
               : 
              
     
                            
               ( 
               int 
               ) Math.ceil(Math.sqrt(w * h / maxNumOfPixels)); 
              
     
                    
               int 
               upperBound = (minSideLength == - 
               1 
               ) ? 
               128 
               : 
              
     
                            
               ( 
               int 
               ) Math.min(Math.floor(w / minSideLength), 
              
     
                            
               Math.floor(h / minSideLength)); 
              
    
                  
                
              
     
                    
               if 
               (upperBound < lowerBound) { 
              
     
                        
               // return the larger one when there is no overlapping zone. 
              
     
                        
               return 
               lowerBound; 
              
     
                    
               } 
              
    
                  
                
              
     
                    
               if 
               ((maxNumOfPixels == - 
               1 
               ) && 
              
     
                            
               (minSideLength == - 
               1 
               )) { 
              
     
                        
               return 
               1 
               ; 
              
     
                    
               } 
               else 
               if 
               (minSideLength == - 
               1 
               ) { 
              
     
                        
               return 
               lowerBound; 
              
     
                    
               } 
               else 
               { 
              
     
                        
               return 
               upperBound; 
              
     
                    
               } 
              
     
               }