VM has run out of memory when retrieving images from cache

The problem I'm handling is known to be on devices with 16 MB of heap memory, and I need to solve it. I have streams receiving images from the server (large images) and caching them, then displayed. The problem is that my memory is running out. To explain a little further, I submit my journal, as well as the code:

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++; } } 

}

From my cache class:

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

From my CacheStore class:

 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; } 

The application crashes on this line: Bitmap bm = BitmapFactory.decodeFile (fileUri.toString ()); where my memory runs out.

My logarithm is:

  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) 

Any help would be greatly appreciated, thanks for reading.

+1
source share
2 answers

You need to try and scale the bitmaps up to insert them into the cache inside your imagedownloader.

In the past, I had to determine the size of an image file before downloading it from the Internet. If it is too big, I just use the default image.

In addition, I also reduced the resolution of the saved image by adjusting the sample size of BitmapFactory and adjusting the size of the final image in the application. (this saved a lot of cache space).

See How to find out the file size 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); } } {...} 

So far this has worked for me, and checking the size of the INSANE files has in many cases saved the application from crashes, not to mention the fact that it can simply skip the massive file in the background.

+2
source

Source: https://habr.com/ru/post/901959/


All Articles