2011-07-06 85 views
1

我正在處理被稱爲是在堆內存16 MB的設備的問題得到的圖像,我需要解決這個問題。我有線程從服務器(大圖像)獲取圖像,並將它們緩存並顯示。問題是我內存不足。爲了解釋遠一點我張貼我的日誌貓以及一些代碼:VM運行內存,同時從緩存

public class Test extends Activity implements OnClickListener { 
ImageView paint, wheels, shadow; 

Button b; 
int j = 2; 
int i = 1; 
String pathToWheels, pathToPaint, pathToShadow; 
String stringAngle; 

/** Called when the activity is first created. */ 
@Override 
public void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    setContentView(R.layout.main); 

    MemoryInfo dbm = new MemoryInfo(); 
    Debug.getMemoryInfo(dbm); 
    b = (Button) findViewById(R.id.button1); 
    b.setOnClickListener(this); 



    wheels = (ImageView) findViewById(R.id.imageView3); 
    paint = (ImageView) findViewById(R.id.imageView2); 
    shadow = (ImageView) findViewById(R.id.imageView1); 



    while (i < 13) { 

     stringAngle = Integer.toString(i); 
     String pathToWheels = url; 
     String pathToPaint = url; 
     String pathToShadow = url; 

     if (Cache.getCacheFile(pathToWheels) == null) { 
      ImageDownloader downloader1 = new ImageDownloader(wheels); 
      downloader1 
        .execute(url); 
     } else if (Cache.getCacheFile(pathToShadow) == null) { 
      ImageDownloader downloader2 = new ImageDownloader(shadow); 
      downloader2 
        .execute(url); 


     } else if (Cache.getCacheFile(pathToPaint) == null) { 

      ImageDownloader downloader = new ImageDownloader(paint); 
      downloader 
        .execute(url); 


     } 

     i++; 


    } 

} 



@Override 
protected void onPause() { 
    super.onPause(); 
    Toast.makeText(getApplicationContext(),"Pause", 
      Toast.LENGTH_SHORT).show(); 

} 

@Override 
public void onClick(View v) { 


    if (v.getId() == R.id.button1) { 
     if (j == 13) 
     { 
      j = 1; 
     } 
     String s = Integer.toString(j); 
     wheels.setImageBitmap(Cache 
       .getCacheFile(url)); 
     paint.setImageBitmap(Cache 
       .getCacheFile(url)); 
    shadow.setImageBitmap(Cache 
       .getCacheFile(url)); 
     j++; 



    } 
} 

}

從我的緩存類:

public static void saveCacheFile(String cacheUri, Bitmap image) { 
    if(!isCacheWritable()) return; 
    Log.i("CACHE S",cacheUri); 
    cache.saveCacheFile(cacheUri, image); 

從我CacheStore類:

public Bitmap getCacheFile(String cacheUri) { 
    if(bitmapMap.containsKey(cacheUri)) return (Bitmap)bitmapMap.get(cacheUri); 

    if(!cacheMap.containsKey(cacheUri)) return null; 
    String fileLocalName = cacheMap.get(cacheUri); 
    File fullCacheDir = new  File(Environment.getExternalStorageDirectory().toString(),cacheDir); 
    File fileUri = new File(fullCacheDir.toString(), fileLocalName); 
    if(!fileUri.exists()) return null; 
    Log.i("CACHE", "File "+cacheUri+" has been found in the Cache"); 
    Bitmap bm = BitmapFactory.decodeFile(fileUri.toString()); 
    Bitmap.createScaledBitmap(bm, 480, 320, true); 
    bitmapMap.put(cacheUri, bm); 
    return bm; 
} 

在此行中的應用程序崩潰:位圖BM = BitmapFactory.decodeFile(fileUri.toString()); 那裏我跑出來的內存。

我的logcat:

07-06 23:40:20.720: ERROR/dalvikvm-heap(1844): 691200-byte external allocation too large for this process. 
07-06 23:40:20.720: ERROR/GraphicsJNI(1844): VM won't let us allocate 691200 bytes 
07-06 23:40:20.770: DEBUG/skia(1844): --- decoder->decode returned false 
07-06 23:40:20.790: DEBUG/AndroidRuntime(1844): Shutting down VM 
07-06 23:40:20.830: WARN/dalvikvm(1844): threadid=1: thread exiting with uncaught exception (group=0x4001d800) 
07-06 23:40:20.890: ERROR/AndroidRuntime(1844): FATAL EXCEPTION: main 
07-06 23:40:20.890: ERROR/AndroidRuntime(1844): java.lang.OutOfMemoryError: bitmap size exceeds VM budget 
07-06 23:40:20.890: ERROR/AndroidRuntime(1844):  at android.graphics.BitmapFactory.nativeDecodeStream(Native Method) 
07-06 23:40:20.890: ERROR/AndroidRuntime(1844):  at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:459) 
07-06 23:40:20.890: ERROR/AndroidRuntime(1844):  at android.graphics.BitmapFactory.decodeFile(BitmapFactory.java:271) 
07-06 23:40:20.890: ERROR/AndroidRuntime(1844):  at android.graphics.BitmapFactory.decodeFile(BitmapFactory.java:296) 
07-06 23:40:20.890: ERROR/AndroidRuntime(1844):  at com.cache.CacheStore.getCacheFile(CacheStore.java:117) 
07-06 23:40:20.890: ERROR/AndroidRuntime(1844):  at com.cache.Cache.getCacheFile(Cache.java:38) 
07-06 23:40:20.890: ERROR/AndroidRuntime(1844):  at com.cache.Test.onClick(Test.java:118) 
07-06 23:40:20.890: ERROR/AndroidRuntime(1844):  at android.view.View.performClick(View.java:2408) 
07-06 23:40:20.890: ERROR/AndroidRuntime(1844):  at android.view.View$PerformClick.run(View.java:8816) 
07-06 23:40:20.890: ERROR/AndroidRuntime(1844):  at android.os.Handler.handleCallback(Handler.java:587) 
07-06 23:40:20.890: ERROR/AndroidRuntime(1844):  at android.os.Handler.dispatchMessage(Handler.java:92) 
07-06 23:40:20.890: ERROR/AndroidRuntime(1844):  at android.os.Looper.loop(Looper.java:123) 
07-06 23:40:20.890: ERROR/AndroidRuntime(1844):  at android.app.ActivityThread.main(ActivityThread.java:4627) 
07-06 23:40:20.890: ERROR/AndroidRuntime(1844):  at java.lang.reflect.Method.invokeNative(Native Method) 
07-06 23:40:20.890: ERROR/AndroidRuntime(1844):  at java.lang.reflect.Method.invoke(Method.java:521) 
07-06 23:40:20.890: ERROR/AndroidRuntime(1844):  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:868) 
07-06 23:40:20.890: ERROR/AndroidRuntime(1844):  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:626) 
07-06 23:40:20.890: ERROR/AndroidRuntime(1844):  at dalvik.system.NativeStart.main(Native Method) 

任何幫助將不勝感激,感謝您的閱讀。

回答

2

您需要重新採樣和縮放你的位圖以前將它們插入到緩存中,您imagedownloader內。

在過去我不得不檢測圖像的文件大小從網站下載它之前。如果它太大,我只使用默認圖像。

此外,我還調整了BitmapFactory採樣大小,並調整了應用程序中最終圖像的大小,從而降低了保存圖像的分辨率。 (這爲緩存節省了很多空間)。

How to know the size of a file before downloading it?

//somewhere inside image downloader class... 
{...} 

BitmapFactory.Options options = new BitmapFactory.Options(); 

if(enableSampling) 
    options.inSampleSize = 2; 

returnBitmap = BitmapFactory.decodeStream(is, null, options); 

if(returnBitmap != null) 
{ 

    if(scaleImage) 
     returnBitmap = Bitmap.createScaledBitmap(returnBitmap, width, height, true); 

    // insert the image into the cache 
    imageCache.put(url, new SoftReference<Bitmap>(returnBitmap)); 


    // Check the ImageView for nulls 
    if(imageView != null && callback != null){ 
     ImageDisplayer displayer = new ImageDisplayer(imageView, returnBitmap, parentView, tag); 
     callback.onImageReceived(displayer); 
    } 

} 

{...} 

到目前爲止,已經爲我工作,併爲INSANE文件大小在檢查崩潰多次保存的應用程序,更何況它可以直接跳過downloaing一個巨大的文件的背景。

+0

對不起,我編輯在崩潰發生我很欣賞的幫助,但。你也可以是一個小更明確,當談到EnableSampling&scaleImage? –

+0

這兩個只是布爾值,我想允許在運行中禁用這些功能。如果圖像足夠小,可以通過頭文件檢測到,並且不需要調整大小,那麼它不會重新採樣並且不會縮放。 –