2011-07-06 42 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

这两个只是布尔值,我想允许在运行中禁用这些功能。如果图像足够小,可以通过头文件检测到,并且不需要调整大小,那么它不会重新采样并且不会缩放。 –