BitmapFactory.decodeFile 上的内存不足

Posted

技术标签:

【中文标题】BitmapFactory.decodeFile 上的内存不足【英文标题】:OutofMemory on BitmapFactory.decodeFile 【发布时间】:2015-06-29 10:06:14 【问题描述】:

在我的应用程序中,我必须将选定的图像上传到 parse.com 以获取他们的 Printout 。 我必须保持图像质量,但我无法调整图像大小。 我必须在 parse.com 中上传图像 ..我不需要在设备屏幕上显示它们(图像来自图像库或来自 facebook 相册..或来自 sdcard)。我无法按要求缩小它们。

我在 BitmapFactory.decodeFile() 上遇到 OutOfMemory 错误。这个bug怎么解决?

正在使用 android:largeHeap="true" 可以解决我的问题吗?

我在三星 SM-G900T 上遇到了这个崩溃,但在模拟器上没有..

我试着放了

BitmapFactory.Options options = new BitmapFactory.Options();
                                options.inJustDecodeBounds = false;
                                options.inPreferredConfig = Config.RGB_565;

但它不起作用。 下面是我的 AsyncTask 类,用于将图像上传到 Parse.com

class UploadFileFromURL extends AsyncTask<String, String, String> 
    ProgressDialog dialog;
    String albumId = "";

    @Override
    protected void onPreExecute() 
        super.onPreExecute();

    


    @Override
    protected String doInBackground(String... f_url) 

        try 
            for (int i = 0; i < arrListImgBean.size(); i++) 

                if (!isUploading || objAsyncUpload.isCancelled()) 
                    break;
                
                try 
                    if (arrListImgBean.get(i).imageStatus == 1)
                        continue;
                    else if (arrListImgBean.get(i).imageStatus == 2) 
                        isPhotodeleted = true;
                        publishProgress("" + countUploaded);
                        deletePhoto(i);

                    

                    else 
                        isPhotodeleted = false;
                        try 

                            Bitmap b = null;
                            InputStream is = null;
                            BitmapFactory.Options options = new BitmapFactory.Options();
                            options.inJustDecodeBounds = false;
                            options.inPreferredConfig = Config.RGB_565; // to
                                                                        // reduce
                                                                        // the
                                                                        // memory
                            options.inDither = true;
                            if (arrListImgBean.get(i).imgURL
                                    .startsWith("http")) 
                                try 
                                    URL url = new URL(
                                            arrListImgBean.get(i).imgURL);
                                    is = url.openConnection()
                                            .getInputStream();
                                 catch (IOException e) 
                                    // TODO Auto-generated catch block
                                    e.printStackTrace();
                                
                                b = BitmapFactory.decodeStream(is, null,
                                        options);

                             else 
                                b = BitmapFactory.decodeFile(
                                        arrListImgBean.get(i).imgURL,
                                        options);
                            

                            // Convert it to byte
                            ByteArrayOutputStream stream = new ByteArrayOutputStream();
                            // Bitmap out = Bitmap.createScaledBitmap(b,
                            // 1500, 2100, false);
                            b.compress(Bitmap.CompressFormat.PNG, 100,
                                    stream);
                            byte[] image = stream.toByteArray();
                            ParseFile file = new ParseFile("Android.png",
                                    image);
                            file.save();
                            String uploadedUrl = file.getUrl();
                            if (uploadedUrl != null) 

                                ParseObject imgupload = new ParseObject(
                                        "Photo");
                                imgupload.put("userName", ParseUser
                                        .getCurrentUser().getEmail());
                                imgupload.put("photoURL", file);
                                imgupload.put("photoID",
                                        arrListImgBean.get(i).imageId);
                                imgupload.put("count", 1);
                                imgupload.put("albumName", albumId);
                                imgupload.save();
                                String objId = imgupload.getObjectId();

                                if (objId != null && !objId.isEmpty()) 
                                    countUploaded++;
                                    publishProgress("" + countUploaded);

                                    database.updateImageStatus(
                                            arrListImgBean.get(i).imageId,
                                            Constants.STATUS_UPLOADED,
                                            objId, uploadedUrl);
                                

                            

                         catch (Exception e) 

                        

                    
                 catch (Exception e) 
                    isUploading = false;
                    e.printStackTrace();
                

            
         catch (Exception e) 
            Log.e("Error: ", e.getMessage());
        
        return null;

    



    @Override
    protected void onPostExecute(String file_url) 
        // dismissDialog(progress_bar_type);
        isUploading = false;
        btnUploadImages.setBackgroundResource(R.drawable.upload_photo);
        vprogress.setCompoundDrawables(null, null, null, null);
        // stopLoading();
        setProgressMsg();

    


【问题讨论】:

在加载到内存时不能缩小图像吗? android:largeHeap="true" 不适用于这种情况。它是为资源丰富的应用程序(如照片编辑软件等)而设计的,这些应用程序使用大量内存。你需要做的是根据设备屏幕缩小图像。 SO中有&gt;1k这样的问题。 我正在寻找解决方案,您可以检查我的代码我已经采取了那些 >1k 问题中建议的所有预防措施@MD 我再问一遍,需要什么画质,需要多大的画质? 【参考方案1】:
android:largeHeap="true"

这行代码可以解决您的问题,但它是一个临时解决方案,但如果图像数量或图像大小增加,可能会再次发生崩溃。更好地使用 Picasso 库来处理图像

【讨论】:

【参考方案2】:

假设您有一个 1024x1024dp 的图像和一个 512x512dp 的设备(这两个数字只是为了便于理解)。因此,在这种情况下,在较小规模的设备上加载全分辨率图像会浪费内存。您可以做的是缩小图像以使其适合设备屏幕。这样不仅可以节省大量内存,而且可以得到正确、清晰、锐利的图像。

我正在添加代码来缩放我目前在我的项目中使用的图像。

final FileInputStream streamIn = new FileInputStream(file);
final BitmapFactory.Options ops = new BitmapFactory.Options();
ops.inJustDecodeBounds = true;
//  Find the correct scale value. It should be the power of 2.
final int REQUIRED_SIZE = 300;
int width_tmp = ops.outWidth, height_tmp = ops.outHeight;
int scale = 1;
while (true) 
      if (width_tmp / 2 < REQUIRED_SIZE || height_tmp / 2 < REQUIRED_SIZE) 
             break;
            
      width_tmp /= 2;
      height_tmp /= 2;
      scale *= 2;
 

 ops.inJustDecodeBounds = false;
 ops.inSampleSize = scale;
 bitmap = BitmapFactory.decodeStream(streamIn, null, ops); //This gets the image
 streamIn.close();

根据设备的屏幕显示尺寸选择REQUIRED_SIZE 值。

【讨论】:

我必须在 parse.com 中上传图像 ..我不需要在设备屏幕上显示它们(图像来自图像库或来自 facebook 相册..)我无法按比例缩小它们根据要求。 什么是“按要求”?确定的尺寸?【参考方案3】:
        try 
            image = readInFile(path);
        
        catch(Exception e)  
            e.printStackTrace();
        

        // Create the ParseFile
        ParseFile file = new ParseFile("picturePath", image);
        // Upload the image into Parse Cloud
        file.saveInBackground();

        // Create a New Class called "ImageUpload" in Parse
        ParseObject imgupload = new ParseObject("Image");

        // Create a column named "ImageName" and set the string
        imgupload.put("Image", "picturePath");


        // Create a column named "ImageFile" and insert the image
        imgupload.put("ImageFile", file);

        // Create the class and the columns
        imgupload.saveInBackground();

        // Show a simple toast message
        Toast.makeText(LoadImg.this, "Image Saved, Upload another one ",Toast.LENGTH_SHORT).show();


 private byte[] readInFile(String path) throws IOException 
     // TODO Auto-generated method stub
     byte[] data = null;
     File file = new File(path);
     InputStream input_stream = new BufferedInputStream(new FileInputStream(
        file));
     ByteArrayOutputStream buffer = new ByteArrayOutputStream();
     data = new byte[16384]; // 16K
     int bytes_read;
     while ((bytes_read = input_stream.read(data, 0, data.length)) != -1) 
         buffer.write(data, 0, bytes_read);
     
     input_stream.close();
     return buffer.toByteArray();

 

【讨论】:

我无法调整图片大小,我的应用是上传它们以进行打印 @NibhaJain 检查我更新的答案,在 image= 这里你会直接得到 byte[],试试这个。

以上是关于BitmapFactory.decodeFile 上的内存不足的主要内容,如果未能解决你的问题,请参考以下文章

BitmapFactory.decodeFile 上的内存不足

Android BitmapFactory.decodeFile(filePath, options) 返回 Null 6.0权限

Android:位图回收()如何工作?

bitmap自己项目中处理遇到的问题

BitmapFactory:无法解码流:java.io.FileNotFoundException

Android 如何使用 BitmapFactory 选项缩放图像