2014-06-30 57 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" 
    ...