2013-01-09 54 views
1

我正在開發一個Android應用程序,它在其多個活動中使用多個大圖像。每張圖片都在1280x800左右,我爲每個活動加載大約2-4張這些圖片。我意識到這些圖像在分配給設備上每個單獨應用程序的內存方面非常大,但是如何以原始分辨率顯示它們而不會遇到java.lang.OutOfMemory錯誤?我需要這些圖像以全尺寸顯示在屏幕上(當屏幕小於圖像時,縮放是由xml自動完成的)。我看到了幾種解決方案,包括將圖像縮小爲縮略圖並將其存儲到內存中,但不會導致圖像失去原始大小/分辨率?謝謝你的幫助!具有大型高分辨率圖像的java.lang.OutOfMemory

回答

1

This article描述頗能如何創建一個堆轉儲和使用Eclipse MAT進行分析。這將幫助您很快找到最有可能發生內存泄漏的嫌疑犯。

我再點你this great link我從另一個問題SO有一個如何正確地來過這個問題教程找到。

3

您可以對此做些事情。

,想到的第一件事是,1280×800的(可能)你的整個屏幕,所以你應該只需要顯示一次一個。當你這樣做的時候,別把別人留在記憶裏。

仍然在每像素4個字節的1280×800圖像僅是4MB,和片劑似乎堆的這些天都提供48MB。如果需要,你應該能夠記住一些內存。如果您的內存不足,可能是您泄漏了。如果您在DDMS中觀看,您在更改活動時是否繼續增加內存使用量?

泄漏的常見原因是位圖本身。完成後請務必致電Bitmap#recycle

如果真的出現這種情況,並且您無法適應所提供的堆空間,您也可以嘗試將android:largeHeap="true"添加到清單中的應用程序標記。這將要求系統爲您提供更多堆空間 - 在某些設備上最高可達256MB。但這應該是最後的手段,因爲它會因設備而異,並且在某些情況下(完全忽略原始的Kindle Fire)。

你可以看到你到底有多少,總堆空間與Runtime.getRuntime().maxMemory();。有關更詳細的解釋,請參見this answer。看到你使用了多少,這很棘手,但如果你想解決那個野獸,那麼有一個描述here

最後,有可能是一個更好的方式來加載圖片比XML指定它們。請務必閱讀此developer guide page。即使您必須將它們留在xml中,我也看到通過將圖像資產分割成drawable-hdpi,drawable-mdpi等目錄,而不是將其轉儲到drawable中,可以顯着改善內存使用情況。

+0

感謝您的回覆,我竟然通過重新保存使用Photoshop我的圖片克服的問題(由於某種原因,將原始圖像進行搞亂了位圖的創建/ Android中的管理流程)。此外,我使用bitmap.recycle()行來更改活動時釋放內存。不幸的是,每當我回到那個活動(使用後退按鈕)時,我會得到一個「嘗試使用回收位圖」的錯誤。我知道我需要重置onResume()方法中的位圖,但我該怎麼做?再次感謝! – NewGradDev

+0

匹配您的創作/回收。如果您在'onStart'中創建位圖,則在'onStop'中回收。如果您在'onResume'中創建它們,請在'onPause'中回收。如果他們通過XML加載,不要打擾回收他們;它在這種情況下由框架處理(但是我相信它們會一直保留在內存中直到onDestroy,這可能與您的應用程序一直存在)。 – dokkaebi

+0

我理解問題的理論部分,但是我會用什麼代碼來實際完成解決方案?我想我不知道如何爲每個ImageView獲取相應的位圖,並在我調用recycle()後將它們鏈接在一起。你能幫我解決這個問題嗎?感謝您的幫助......這是我在啓動我的應用程序之前需要克服的最後一個障礙,如果您可以幫助我使用此代碼,那將是非常棒的。 :) – NewGradDev

0

圖像需要在使用BitmapFactory或相關方法加載圖像之前進行縮放。

public static int calculateInSampleSize(
      BitmapFactory.Options options, int reqWidth, int reqHeight) { 
    // Raw height and width of image 
    final int height = options.outHeight; 
    final int width = options.outWidth; 
    int inSampleSize = 1; 

    if (height > reqHeight || width > reqWidth) { 
     if (width > height) { 
      inSampleSize = Math.round((float)height/(float)reqHeight); 
     } else { 
      inSampleSize = Math.round((float)width/(float)reqWidth); 
     } 
    } 
    return inSampleSize; 
} 

public static Bitmap decodeSampledBitmapFromResource(Resources res, int resId, 
     int reqWidth, int reqHeight) { 

    // First decode with inJustDecodeBounds=true to check dimensions 
    final BitmapFactory.Options options = new BitmapFactory.Options(); 
    options.inJustDecodeBounds = true; 
    BitmapFactory.decodeResource(res, resId, options); 

    // Calculate inSampleSize 
    options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight); 

    // Decode bitmap with inSampleSize set 
    options.inJustDecodeBounds = false; 
    return BitmapFactory.decodeResource(res, resId, options); 
} 

整個事情是在Android開發者網站上解釋說,Loading Large Bitmaps Efficiently