0

原本一切都很好。我一直在努力與5個繪製資源目錄與可繪製資源直接配置有關的Android內存不足崩潰

drawable-hdpi 
drawable-ldpi 
drawable-mdpi 
drawable-xhdpi 
drawable-xxhdpi 
我由Eclipse ADT-軟件包時,我創建了一個新的項目最近創建的

。所以當我需要一個新的位圖時,我一直在把這個位圖的一個副本放到這5個目錄中的每一箇中。對我來說,這似乎有點奇怪,所以我很高興通過閱讀the Android documentation Providing Resources發現我可以爲所有常見位圖設置一個「drawable」目錄。所以我切換到

drawable 
drawable-hdpi 
drawable-ldpi 
drawable-mdpi 
drawable-xhdpi 
drawable-xxhdpi 

是留在原來的5個目錄是「ic_launcher.png」文件已經爲我創建的項目最初創建時的唯一文件。

但是,可繪製目錄的新配置失敗了。裝載了一個36K位圖文件frame.png,存儲器外的錯誤發生現在作爲行

bitmap_fancyframe = BitmapFactory.decodeResource(getResources(), R.drawable.frame); 

的logcat的顯示,Android現在試圖分配一個字節6790156存儲器塊作爲結果的結果線(這是在logcat底部提到的線DrawOnTop.java:95)

06-01 07:26:53.995: I/dalvikvm-heap(1530): Forcing collection of SoftReferences for 6790156-byte allocation 
06-01 07:26:54.025: D/dalvikvm(1530): GC_BEFORE_OOM freed 9K, 14% free 53820K/62343K, paused 27ms, total 27ms 
06-01 07:26:54.025: E/dalvikvm-heap(1530): Out of memory on a 6790156-byte allocation. 
06-01 07:26:54.025: I/dalvikvm(1530): "main" prio=5 tid=1 RUNNABLE 
06-01 07:26:54.025: I/dalvikvm(1530): | group="main" sCount=0 dsCount=0 obj=0x41077508 self=0x40de49a0 
06-01 07:26:54.025: I/dalvikvm(1530): | sysTid=1530 nice=0 sched=0/0 cgrp=apps handle=1075179312 
06-01 07:26:54.025: I/dalvikvm(1530): | schedstat=(681383064 1229707806 4777) utm=53 stm=14 core=0 
06-01 07:26:54.025: I/dalvikvm(1530): at android.graphics.BitmapFactory.nativeDecodeAsset(Native Method) 
06-01 07:26:54.025: I/dalvikvm(1530): at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:623) 
06-01 07:26:54.025: I/dalvikvm(1530): at android.graphics.BitmapFactory.decodeResourceStream(BitmapFactory.java:476) 
06-01 07:26:54.025: I/dalvikvm(1530): at android.graphics.BitmapFactory.decodeResource(BitmapFactory.java:499) 
06-01 07:26:54.025: I/dalvikvm(1530): at android.graphics.BitmapFactory.decodeResource(BitmapFactory.java:529) 
06-01 07:26:54.025: I/dalvikvm(1530): at com.example.MyApp.DrawOnTop.<init>(DrawOnTop.java:95) 

任何人都可以解釋爲什麼會發生這種情況?更重要的是,這個frame.png文件在我的代碼中被縮放和拉伸,所以我真的不需要它的5個副本,所以有沒有什麼辦法可以在沒有這些類型的'drawable'目錄中擁有所有常見的png位圖的問題?

更新感謝來自@sam的評論以及來自@ ken-wolf的回答,我現在明白如果正確類型的位圖不可用,Android會執行大量的位圖縮放。因此,當我簡單地在所有目錄之間複製相同的位圖時,我的新理解是,這樣做的效果是位圖將不加縮放地加載。在這個縮放過程​​中,有些事情顯然是錯誤的,但是由於我在做自己的縮放,所以我也不需要Android來做。所以我現在認爲重要的問題是:如何設置我的應用程序,以便只提供每個位圖的一個版本,並指示Android不要執行任何位圖縮放

+1

http://static.googleusercontent.com/external_content/untrusted_dlcp/www.google.co m/en // events/io/2011/static/presofiles/memory_management_for_android_apps.pdf – Sam

回答

1

爲每個相應文件夾中的每個圖像提供不同大小的版本(實際寬度x高度像素大小)是一種很好的做法。這可確保Android根據設備選擇適當的圖像以傳送最清晰的圖像。您可以將它們全部放在/drawable/文件夾中,但這會導致模糊的圖像 - 這在密度更高的情況下尤其明顯。請再次閱讀它,並對其進行解釋:Supporting Multiple Screens

「默認」資源是那些未用配置限定符標記的資源。例如,drawable /中的資源是默認的可繪製資源。系統假定默認資源是爲基準屏幕尺寸和密度設計的,這是正常的屏幕尺寸和中等密度。因此,系統會根據情況縮放高密度屏幕的默認密度資源,降低低密度屏幕的密度資源。

至於位圖內存不足錯誤,這是與Android上的內存分配有關的複雜問題。不幸的是,您無法事先準確地分辨出您有多少內存可用,並將Bitmap放入內存中相當昂貴。不知道你的應用程序的其餘很難給出一個確切的解決方案,但也有可以採取以確保不會發生這種情況的防禦措施,其中包括:

  • 製作一個全球性的,靜態參考位圖,再 - 使用它
  • 確保您從視圖刪除該位圖的任何引用,並呼籲Bitmap.recycle()當你用它
  • 進行使用Memory Cache
+0

感謝您的有用評論:-)。儘管你的想法沒有幫助解決內存不足的錯誤。導致內存不足的png文件在磁盤上只有36kb,因此係統正在尋找分配6790156的事實對我來說似乎很荒謬,因爲[支持多個屏幕]上的信息(http://developer.android .com/guide/practices/screens_support.html#support)通過訂購1個因素(0.5,0.75等)來說明縮放比例。整個應用程序工作正常,沒有消耗太多的內存,如果我只是複製所有不同的可繪製目錄的位圖。 – Stochastically

+0

我不是專家,如何分配內存的內部工作在Android上,但跨所有文件夾複製相同的位圖似乎是錯誤的。直覺上我覺得讓系統爲你的設備使用最接近可能的「正確」尺寸*,而不是放大或縮小,會更好。我不知道你在測試什麼設備?可能是因爲你的大位圖縮小了比例,導致了這個問題。 –

+0

確實,直覺上我也覺得不對。我正在測試[Samsung Galaxy S4](http://www.samsung.com/uk/support/model/GT-N7105RWDCOV)這麼一款新手機(並且僅針對API版本14及以上版本開發),所以我認爲這會升級而不是縮小。 – Stochastically

2

直行到這裏問題的心臟:

我如何設置我的應用程序,從而提供只有一個版本,每個位的...

只要把你的位圖的drawable目錄的只有一個。我相信它必須是DPI比目標設備小的DPI。但是,Android會爲具有更大DPI的設備在內存中創建縮放版本。我也相信,如果您只使用drawable目錄,則Android會將其設置爲中等DPI,並將其與drawable-mdpi相比得到相同的結果。請注意,縮放後的圖像的真實尺寸(以像素數爲單位)不同,但大小與英寸/ DP大致相同。在xxhdpixxxhdpi屏幕上,內存版本最終可能會非常龐大​​。例如,我從產品的iPhone Retina版本獲得了640x960背景圖像。 (這可能屬於hdpi,我應該生成更小的版本)。如果你把它放在drawable-mdpi的Android上,它會在一個xxhdpi設備上縮小3倍,所以它最終爲1920x2880,每像素32位,這是我認爲的22兆。

並指示Android不做任何位圖縮放。

要在加載時不執行位圖縮放,請使用drawable-nodpi目錄。您必須在繪圖時或在您的佈局中手動縮放(使用android:scaleType="fitXY"或類似的方法,並且如果您有任何代碼查詢圖像大小,它將始終返回相同的像素數。質量不可察覺地不同(如果這是隻有大小)性能明顯更好,並且內存中沒有巨大的圖像,只有原始大小的圖像