最大尺寸图像,以避免在Android上出现OutOfMemoryException

时间:2014-12-05 14:44:10

标签: android bitmap out-of-memory

我觉得很难处理OutOfMemoryExceptions很难在Android中管理。 现在,我总是首先在PhotoShop中调整图像大小,然后检查不同的设备和模拟器,看看我能在多大程度上突破极限。

我当前应用程序的目标是在其上输入输入图像,地图文本和图像并将其保存为PDF。 现在我正在使用大约620x842和250kb的图像,输出不够好。 原版是2480x3368和482kb。

毫无疑问,使用原始文件会导致OutOfMemoryExceptions。 但我想知道如何关闭我可以得到原来的。

有关此的任何想法或提示吗?

5 个答案:

答案 0 :(得分:3)

  

原作是2480x3368和482kb

您的图像大小和文件大小令人困惑。 482KB是文件的大小,是压缩图像。

2480x3368在32位ARGB中实际上是33MB。 (这对于内存中的单个对象来说很重要,可以立即分配)

文件的大小与图像占用的内存大小无关。

Nota:这有点偏离主题,可能应该是评论,但对评论格式来说太长了。

答案 1 :(得分:1)

您是否正在根据google guide解码文件?这为我解决了outOfMemoryException的问题。现在我可以轻松解码像 星系SII上的2676x3326

答案 2 :(得分:0)

您可以在调用BitmapFactory.decodeFile(String,Options)时使用Bitmap.Options

通过设置inSampleSize = 2,您可以获得尺寸除以2的结果位图。

答案 3 :(得分:0)

你可以试试这个:

 <activity
            android:name="..."
            android:configChanges="orientation|keyboardHidden"
            android:hardwareAccelerated="true"
            android:label="@string/app_name"
            android:largeHeap="true" >
        </activity>

有时候它会起作用,有时它会起作用。请记住,此大小是特定于设备的,因此如果您希望应用程序公开,则应调整所有所需大小的图像大小。我见过的最低价是三星银河的名气。它的heep不会加载大于2048x2048的图像。

如果您想加载大量图片并且内存不足,可以尝试使用thirparty lib,如:http://square.github.io/picasso/。它对我来说非常好,并处理android nativly所有的位图问题。

真正的问题是图片的大小。即使图片具有300kb或400kb的尺寸,当你将其放大以适应屏幕尺寸时,它也会变成非常大的位图,如20或30 mb,这将溢出该线程的堆。

答案 4 :(得分:0)

您可以使用BitmapFactory获取图像的边界,然后加载适合当前内存的较小版本的图像:

     /**
     * Decodes the given inputstream into a Bitmap, scales the bitmap to the
     * required height and width if image dimensions are bigger. Note: the
     * decoder will try to fulfill this request, but the resulting bitmap may
     * have different dimensions that precisely what has been requested.
     *
     * @param _inputStreamJustDecode The input stream for bound decoding
     * @param _inputStreamData The input stream for image decoding
     * @param _preview true to generate a preview image, false to generate a high quality image
     * @return
     */
    private Bitmap decodeSampledBitmapFromResource(InputStream _inputStreamJustDecode,InputStream _inputStreamData) {

        // First decode with inJustDecodeBounds=true to check dimensions
        final BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;
        BitmapFactory.decodeStream(_inputStreamJustDecode, null, options);
        float imageSize = options.outWidth * options.outHeight * 4;
        float scaleFactor = 1;
        long availableMem = getAvailableMemory(mContext);

        //new image should not use more than 66% of the available memory
        availableMem*=0.66f;
        if(imageSize > availableMem){
            scaleFactor = (float)availableMem / imageSize;
        }

        float maxDimen = options.outWidth > options.outHeight ? options.outWidth : options.outHeight;

        //Don't let the image get to big.
        if(maxDimen * scaleFactor > Constant.MAX_TEXTURE_SIZE ){
            scaleFactor = Constant.MAX_TEXTURE_SIZE/maxDimen;
        }

        // Calculate inSampleSize
        options.inSampleSize = calculateInSampleSize(options, options.outWidth*scaleFactor,
                options.outHeight*scaleFactor);

        // Decode bitmap with inSampleSize set
        options.inJustDecodeBounds = false;
        // set other options
        options.inPurgeable = true;
        options.inPreferredConfig = Bitmap.Config.RGB_565;
        return BitmapFactory.decodeStream(_inputStreamData,null,options);
    }

     /**
     * Returns the currently available memory (ram) in bytes.
     * @param _context The context.
     * @return The available memory in bytes.
     */
    public long getAvailableMemory(Context _context){
        ActivityManager.MemoryInfo mi = new ActivityManager.MemoryInfo();
        ActivityManager activityManager = (ActivityManager) _context.getSystemService(Activity.ACTIVITY_SERVICE);
        activityManager.getMemoryInfo(mi);
        long availableMegs = mi.availMem;
        return availableMegs;
    }

注意:两个输入流都来自同一个资源,但由于在解码边界后无法回放流,因此需要一个新流。