Android ImageView图片浏览器(ImageView加载sd卡图片资源)的内存溢出问题分析

方式一:利用Bitmap加载图片字节流的方式显示图片

定义:

 

       private BitmapFactory.Options opt=new BitmapFactory.Options(); 
       private Bitmap bitmap = null;
       private ImageView mimageview ; 
       mimageview = (ImageView)this.findViewById(R.id.pic_voice_image); 

加载图片

	private void LoadPicture() {	   
	    options=new Options();
	    options.inDither=false;    /*不进行图片抖动处理*/
	    options.inPreferredConfig=null;  /*设置让解码器以最佳方式解码*/
	    options.inSampleSize=1;          /*图片长宽方向缩小倍数*/
	    bitmap = BitmapFactory.decodeFile(path,options);//其中path是图片路径
	    mimageview.setImageBitmap(bitmap);
	}

在需要加载图片的地方执行:

mimageview.setImageBitmap(bitmap);

测试效果:图片在1M左右以及以下的时候切换是没问题的,但是一旦图片达到了3M的时候Bitmap内存就溢出了。虽然说Bitmap的内存是8M,但是实际上会有误差,切换图片时系统还来不及回收Bitmap上一次资源完毕又要往里面写流,导致oom错误。所以这种方法还不是很优的方法。
 

 

方式二:利用BitmapFactory.decodeStream加载IInputStream图片字节流的方式显示图片

这种方式相对第一种方式来说会更节省内存,方法如下:

    /** 
     * 以最省内存的方式读取本地资源的图片 
     */  
    public static Bitmap readBitMap(String path,BitmapFactory.Options opt,InputStream is){  
        opt.inPreferredConfig = Bitmap.Config.RGB_565;   
        opt.inPurgeable = true;  
        opt.inInputShareable = true;  
        opt.inSampleSize=2;//二分之一缩放,可写1即100%显示
        //获取资源图片  
	try {
	  is = new FileInputStream(path);
	} catch (FileNotFoundException e) {
	  e.printStackTrace();
	}  
     return BitmapFactory.decodeStream(is,null,opt);  
    } 


在需要加载图片的地方执行:

mimageview.setImageBitmap(readBitMap(path,opt,is));


测试结果:3M的大图切换没问题,相对第一种来说优点是完全不用考虑切换大图时Bitmap内存不及回收内存导致内存溢出问题,只要做好InputStream流的开关操作就好了。

 

方式三:利用BitmapFactory.decodeStream通过按比例压缩方式显示图片

这种方式相对第二种方式来说会更优化,因为一旦图片超过了3M,甚至更大的时候方式二也是不管用的。以下的方法是按着设定的分辨率让如片按比例压缩,保证不管是多大的图片也能无压力显示出来。以下是完整代码:

	/***********
	 * @获得原始流*
	 ***********/
	public  InputStream toInputStream(String path) throws Exception{
		FileInputStream is = new FileInputStream(path.replace("file://", ""));
        return is;
	}
	/************
	 * 返回压缩后的流*
	 ************/
	public Bitmap toBitmap(String path, int reqWidth, int reqHeight) throws Exception{
		Bitmap bm = null;
		InputStream inputStream = toInputStream(path);  // 远程读取输入流
		if (inputStream == null){
			return null;
		}
		BitmapFactory.Options options = new BitmapFactory.Options();	
        // 当inJustDecodeBounds设为true时,不会加载图片仅获取图片尺寸信息
        options.inJustDecodeBounds = true;       
        // 获取图片大小
        BitmapFactory.decodeStream(inputStream, null, options);      
        // 获取图片压缩比
		int size = calculateInSampleSize(options, reqWidth, reqHeight);
		if ( size < 0 ){
			return null;
		}	
		Log.e("size", String.valueOf(size));
		options.inSampleSize = size;   // 找到合适的倍率
		// 当inJustDecodeBounds设为false,加载图片到内存
		options.inJustDecodeBounds = false; 
		inputStream = toInputStream(path);  // 远程读取输入流,要再读一次,否则之前的inputStream已无效了
		bm = BitmapFactory.decodeStream(inputStream, null, options);		
		return bm;
    }
	/*********************************
	 * @function: 计算出合适的图片倍率
	 * @options: 图片bitmapFactory选项
	 * @reqWidth: 需要的图片宽
	 * @reqHeight: 需要的图片长
	 * @return: 成功返回倍率, 异常-1 
	 ********************************/
	private  int calculateInSampleSize(Options options, int reqWidth,
			int reqHeight) {		
		// 设置初始压缩率为1
	    int inSampleSize = 1;    
		try{
	        // 获取原图片长宽
	        int width = options.outWidth;
	        int height = options.outHeight;        
	        // reqWidth/width,reqHeight/height两者中最大值作为压缩比
	        int w_size = width/reqWidth;
	        int h_size = height/reqHeight;
	        inSampleSize = w_size>h_size?w_size:h_size;  // 取w_size和h_size两者中最大值作为压缩比
	        Log.e("inSampleSize", String.valueOf(inSampleSize));
		}catch(Exception e){
			return -1;
		}
		return inSampleSize;
	}	


在需要加载图片的地方执行:

mimageview.setImageBitmap(toBitmap(path, picwidth, picheigth));

测试该方法可以显示出来很大的图片,只要你设定的长宽合理。

你可能感兴趣的:(android)