2014-06-30 59 views
1

我想将图片加载到图像视图中,以便我可以切换图片。图片路径保存在一个数据库中,该数据库引用到我的项目中。因此,当我将图片加载到项目中并重新打开项目时,图片仍然可见,因为它们存储在数据库中。加载图片时出现OutOfMemoryException

我的问题是,我总是遇到OutOfMemoryException只有3张图片。我试图将inSampleSize减少到一个较低的值。但是,即使为15的inSampleSize,图片的最大数量可以是3

予测得的位图的分配的大小与getAllocationByteCount()对于不同inSampleSizes:

  • 15980544字节= 15 MB(inSample 1 )|| 998784字节=由于图片的0.95 MB(inSample 4)
  • 249696字节= 0.23 MB(inSample 15)|| 27744字节= 0.02 MB(insample 30)

旋转(90°逆时针)予旋转他们与matrix.postRotate(90)和矩阵我创建一个新的位图。我用bitmap.recyle()删除旧的位图。新的位图的大小为499392字节= 0.47 MB​​

首先我开始一个摄像头意图:

// capturePicture() soll die Kamera starten und ein neues Bild soll gemacht werden können 
private void capturePicture() { 

    // erstelle einen neuen Intent, damit sich die Kamera öffnet 
    // mit MediaStore.ACTION_IMAGE_CAPTURE wird angewiesen die Kamera zu starten 
    CameraIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); 

    // Sicherstellen, dass auf dem Handy eine Kamera installiert ist 
    if (CameraIntent.resolveActivity(getPackageManager()) != null) { 


     photoFile = null; 


     try { 
      // rufe die Methode createImageFile() auf, damit die Aufnahme in eine Datei gespeichert werden kann 
      photoFile = createImageFile(); 


     } catch (IOException ex) { 

      // wenn das Erstellen des Bildes fehlschlug 
      Toast.makeText(thisActivity,"Bilddatei konnte nicht erstellt werden", 
        Toast.LENGTH_LONG).show(); 
     } 

     // wenn es eine Datei gibt, soll diese in der ImageView angezeigt werden 
     if (photoFile != null) { 
      CameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(photoFile)); 

      // rufe die onActivityForResult() Methode mit einer ID auf, um das Bild in der ImageView anzeigen zu können 
      this.savePicture(photoFile.getAbsolutePath(), photoFile.getName()); 
      startActivityForResult(CameraIntent, REQUEST_TAKE_PHOTO); 
      //bitmap.recycle(); 
      //System.gc(); 
      this.reloadPicDB(); 
     } 


    } else { 

     // TODO: auf den Play Store mit einer Kamera App verweisen 
     Toast.makeText(thisActivity,"Sie haben leider keine Kamera installiert", Toast.LENGTH_SHORT).show(); 
    } 

    photoCount++; 

} 

在这种方法我调用该方法createImageFile()为了创建一个镜像文件:

// erstellt eine Datei nachdem ein Foto gemacht wurde und gibt diese zurück 
    private File createImageFile() throws IOException { 

     // TODO: Sinnvollen Dateinamen für die Bilddateien geben 
     //String timeStamp = new SimpleDateFormat("ddMMyyyy_HHmmss").format(new Date()); 

     imageFileName = "JPEGNEU"; 

     // TODO: überlegen, wohin die Bilddateien gespeichert werden sollen 
     //File storageDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES); 
     File pictureStorageDir = new File("/sdcard/neu/"); 

     // In der Datei pictureImage werden der Name, Endung und Verzeichnis gespeichert   
     File pictureImage = File.createTempFile(imageFileName, /* prefix */ 
       ".jpg", /* suffix */ 
       pictureStorageDir /* directory */ 
     ); 

     // ermittle den absoluten Pfad der Bilddatei und speichere diesen in den String PhotoPath 
     PhotoPath = pictureImage.getAbsolutePath(); 

     // gebe die Bilddatei zurück, damit dieses in der Methode capturePicture weiter verwendet werden kann 
     return pictureImage; 

    } 

图片将在onActivityResult()方法来示出:

if(requestCode == REQUEST_TAKE_PHOTO){ 


      ImageView beispiel = (ImageView) findViewById(R.id.beispiel); 
BitmapFactory.Options options1 = new BitmapFactory.Options(); 
      options1.inSampleSize = 15;  //1/12 des Bildes zu laden 

options1.inPreferredConfig = Config.ARGB_4444; 
      Bitmap image = BitmapFactory.decodeFile(PhotoPath, options1); 
      Log.d("Speicherausgabe", "Speicherausgabe0.1 " + image.getAllocationByteCount()); 
Matrix matrix = new Matrix(); 
      matrix.postRotate(90); 

      bitmap = Bitmap.createBitmap(image, 0, 0, image.getWidth() , image.getHeight(), matrix, true); 
image.recycle(); 
      System.gc(); 

if(zaehlerRequestPhoto == 0){ 
beispiel.setImageBitmap(bitmap); 
} else { 
       beispiel.setImageBitmap(bitmap); 
       Log.d("Speicherausgabe", "Speicherausgabe3 " + bitmap.getAllocationByteCount()); 
       //System.gc(); 




      } 

在这种情况下,我应该如何避免OutOfMemoryException?

回答

0

我问这个问题之前Here

但我仍然不能完全解决问题,但能够得益于降低强度与下面的代码,@Binh陈

public Bitmap decodeSampledBitmapFromResourceMemOpt(
      InputStream inputStream, int reqWidth, int reqHeight) { 

     byte[] byteArr = new byte[0]; 
     byte[] buffer = new byte[1024]; 
     int len; 
     int count = 0; 

     try { 
      while ((len = inputStream.read(buffer)) > -1) { 
       if (len != 0) { 
        if (count + len > byteArr.length) { 
         byte[] newbuf = new byte[(count + len) * 2]; 
         System.arraycopy(byteArr, 0, newbuf, 0, count); 
         byteArr = newbuf; 
        } 

        System.arraycopy(buffer, 0, byteArr, count, len); 
        count += len; 
       } 
      } 

      final BitmapFactory.Options options = new BitmapFactory.Options(); 
      options.inJustDecodeBounds = true; 
      BitmapFactory.decodeByteArray(byteArr, 0, count, options); 

      options.inSampleSize = calculateInSampleSize(options, reqWidth, 
        reqHeight); 
      options.inPurgeable = true; 
      options.inInputShareable = true; 
      options.inJustDecodeBounds = false; 
      options.inPreferredConfig = Bitmap.Config.ARGB_8888; 

      int[] pids = { android.os.Process.myPid() }; 
      MemoryInfo myMemInfo = mAM.getProcessMemoryInfo(pids)[0]; 
      Log.e(TAG, "dalvikPss (decoding) = " + myMemInfo.dalvikPss); 

      return BitmapFactory.decodeByteArray(byteArr, 0, count, options); 

     } catch (Exception e) { 
      e.printStackTrace(); 

      return null; 
     } 
    } 
The method that does the calculation: 

public void onButtonClicked(View v) { 
     int[] pids = { android.os.Process.myPid() }; 
     MemoryInfo myMemInfo = mAM.getProcessMemoryInfo(pids)[0]; 
     Log.e(TAG, "dalvikPss (beginning) = " + myMemInfo.dalvikPss); 

     long startTime = System.currentTimeMillis(); 

     FileInputStream inputStream; 
     String filePath = Environment.getExternalStorageDirectory() 
       .getAbsolutePath() + "/test2.png"; 
     File file = new File(filePath); 
     try { 
      inputStream = new FileInputStream(file); 
//   mBitmap = decodeSampledBitmapFromResource(inputStream, 800, 800); 
      mBitmap = decodeSampledBitmapFromResourceMemOpt(inputStream, 800, 
        800); 
      ImageView imageView = (ImageView) findViewById(R.id.image); 
      imageView.setImageBitmap(mBitmap); 
     } catch (FileNotFoundException e) { 
      e.printStackTrace(); 
     } 
     myMemInfo = mAM.getProcessMemoryInfo(pids)[0]; 
     Log.e(TAG, "dalvikPss (after all) = " + myMemInfo.dalvikPss 
       + " time = " + (System.currentTimeMillis() - startTime)); 
    } 
1

内存不足异常通常发生在应用程序资源超过可用堆内存的情况下。特别是位图使用更多的内存,并且它的缓存不会被清除,直到达到最大内存并且垃圾收集器完成其工作。因此,请使用LruCache避免内存不足异常,或者只需使用此库中的Universal Image Loader即可。 https://github.com/nostra13/Android-Universal-Image-Loader

1

一旦你准备好与你的形象,你应该回收,零它象下面这样:

image.recycle(); 
image=null; 

OR

你也可以通过添加到您AndroidManifest增加堆空间:

<application 
    android:label="@string/app_name" 
    android:largeHeap="true" 
    ...