当前位置: 代码迷 >> Android >> Android缩放图片文件引起的OOM错误(转)
  详细解决方案

Android缩放图片文件引起的OOM错误(转)

热度:33   发布时间:2016-05-01 16:38:05.0
Android缩放图片文件引起的OOM异常(转)
原文地址:http://www.blogjava.net/anymobile/articles/340722.html
传输文件,或者设置头像,我们一般都会检查原始图片的大小,作缩放处理。

常用的Android版缩放图片代码:

view plaincopy to clipboardprint?
ContentResolver cr = this.getContentResolver(); 
try 

    InputStream in = cr.openInputStream(uri); 
    Bitmap bitmap = BitmapFactory.decodeStream(in); 
    try 
    { 
        in.close(); 
    } 
    catch (IOException e) 
    { 
        e.printStackTrace(); 
    } 
    if(null  == bitmap) 
    { 
        Toast.makeText(this, "Head is not set successful,Decode bitmap failure", 2000); 
    } 
    //原始图片的尺寸 
    int bmpWidth  = bitmap.getWidth(); 
    int bmpHeight = bitmap.getHeight(); 
     
    //缩放图片的尺寸 
    float scaleWidth  = (float) 40 / bmpWidth; 
    float scaleHeight = (float) 40 / bmpHeight; 
    Matrix matrix = new Matrix(); 
    matrix.postScale(scaleWidth, scaleHeight); 
     
    //产生缩放后的Bitmap对象 
    Bitmap resizeBitmap = Bitmap.createBitmap( 
        bitmap, 0, 0, bmpWidth, bmpHeight, matrix, false); 
    bitmap.recycle(); 
    //Bitmap to byte[] 
    byte[] photoData = Bitmap2Bytes(resizeBitmap); 
     
    //save file 
    String fileName = "/sdcard/test.jpg"; 
    FileUtil.writeToFile(fileName, photoData); 
     
    //save photo check sum to db 
    DataCenter.GetInstance().ModifyIMMUser(); 
    //refresh ImageView 

catch (FileNotFoundException exp) 

    exp.printStackTrace(); 

如果图片非常大,在执行BitmapFactory.decodeStream的时候就会抛出OOM异常。
我们来看看系统应用MMS是如何处理的,SMS添加了多媒体附件后就作MMS处理了,当附加文件原图超过300K,也会做个缩放处理,具体参考:com.android.mms.ui/.UriImage:

view plaincopy to clipboardprint?
package com.android.mms.ui; 
public class UriImage 

    private int mWidth; 
    private int mHeight; 
    ... ... 
    // 
    private void decodeBoundsInfo() 
    { 
        InputStream input = null; 
        try 
        { 
            input = mContext.getContentResolver().openInputStream(mUri); 
            BitmapFactory.Options opt = new BitmapFactory.Options(); 
            opt.inJustDecodeBounds = true;//只描边,不读取数据 
            BitmapFactory.decodeStream(input, null, opt); 
            mWidth = opt.outWidth; 
            mHeight = opt.outHeight; 
        } 
        catch (FileNotFoundException e) 
        { 
            // Ignore 
            Log.e(TAG, "IOException caught while opening stream", e); 
        } 
        finally 
        { 
            if (null != input) { 
                try { 
                    input.close(); 
                } catch (IOException e) { 
                    // Ignore 
                    Log.e(TAG, "IOException caught while closing stream", e); 
                } 
            } 
        } 
    } 
    private byte[] getResizedImageData(int widthLimit, int heightLimit) 
    { 
        int outWidth = mWidth; 
        int outHeight = mHeight; 
        int s = 1; 
        while ((outWidth / s > widthLimit) || (outHeight / s > heightLimit)) 
        { 
            s *= 2; 
        } 
        //先设置选项 
        BitmapFactory.Options options = new BitmapFactory.Options(); 
        //returning a smaller image to save memory. 
        options.inSampleSize = s; 
        InputStream input = null; 
        try 
        { 
            input = mContext.getContentResolver().openInputStream(mUri); 
            Bitmap b = BitmapFactory.decodeStream(input, null, options);//注意看options的用法 
            if (b == null) { 
                return null; 
            } 
            ByteArrayOutputStream os = new ByteArrayOutputStream(); 
            b.compress(CompressFormat.JPEG, MessageUtils.IMAGE_COMPRESSION_QUALITY, os); 
            return os.toByteArray(); 
        } catch (FileNotFoundException e) { 
            Log.e(TAG, e.getMessage(), e); 
            return null; 
        } finally { 
            if (input != null) { 
                try { 
                    input.close(); 
                } catch (IOException e) { 
                    Log.e(TAG, e.getMessage(), e); 
                } 
            } 
        } 
    } 
    ... ... 

可以看出,MMS应用的方法是:先设置缩放选项,再读取缩放的图片数据到内存,规避了内存引起的OOM。
修改后的代码:

view plaincopy to clipboardprint?
    ContentResolver cr = this.getContentResolver(); 
    try 
    { 
        InputStream in = cr.openInputStream(uri); 
           BitmapFactory.Options options = new BitmapFactory.Options(); 
           options.inJustDecodeBounds = true; 
           BitmapFactory.decodeStream(in, null, options); 
        try 
        { 
    in.close(); 

        catch (IOException e) 
        { 
    e.printStackTrace(); 

           int mWidth = options.outWidth; 
           int mHeight = options.outHeight; 
            
           int sWidth  = 40; 
           int sHeight = 40; 
            
        int s = 1; 
        while ((mWidth / s > sWidth * 2) || (mHeight / s > sHeight * 2)) 
        { 
            s *= 2; 
        } 
           options = new BitmapFactory.Options(); 
        options.inSampleSize = s; 
        in = cr.openInputStream(uri); 
        Bitmap bitmap = BitmapFactory.decodeStream(in, null, options); 
        try 
        { 
    in.close(); 

        catch (IOException e) 
        { 
    e.printStackTrace(); 

        if(null  == bitmap) 
        { 
            Toast.makeText(this, "Head is not set successful,Decode bitmap failure", 2000); 
            return ; 
        } 
        //原始图片的尺寸 
        int bmpWidth  = bitmap.getWidth(); 
        int bmpHeight = bitmap.getHeight(); 
         
        //缩放图片的尺寸 
        float scaleWidth  = (float) sWidth / bmpWidth; 
        float scaleHeight = (float) sHeight / bmpHeight; 
        Matrix matrix = new Matrix(); 
        matrix.postScale(scaleWidth, scaleHeight); 
         
        //产生缩放后的Bitmap对象 
        Bitmap resizeBitmap = Bitmap.createBitmap( 
            bitmap, 0, 0, bmpWidth, bmpHeight, matrix, false); 
        bitmap.recycle(); 
                Bitmap resizeBitmap = bitmap; 
        //Bitmap to byte[] 
        byte[] photoData = bitmap2Bytes(resizeBitmap); 
         
        //save file 
        String fileName = "/sdcard/test.jpg"; 
        FileUtil.writeToFile(fileName, photoData); 
view plaincopy to clipboardprint?
private byte[] bitmap2Bytes(Bitmap bm) 

    ByteArrayOutputStream baos = new ByteArrayOutputStream(); 
    bm.compress(Bitmap.CompressFormat.JPEG, 100, baos); 
    return baos.toByteArray(); 
  相关解决方案