Reputation: 9020
I am working on an application where i have images being downloaded asynchronously for SlideShows. One SlideShow contains 10 slides, hence 10 images are downloaded when slideshow is opened. After i scroll through 10-15 slideshows approximately i start getting memory warning and following Exception in the trace and app crashes.
Here is the trace:
12-23 12:23:53.124: ERROR/dalvikvm-heap(3067): 45850-byte external allocation too large for this process.
12-23 12:23:53.134: ERROR/dalvikvm(3067): Out of memory: Heap Size=13127KB, Allocated=11913KB, Bitmap Size=11407KB
12-23 12:23:53.134: ERROR/GraphicsJNI(3067): VM won't let us allocate 45850 bytes
12-23 12:23:53.134: DEBUG/skia(3067): --- decoder->decode returned false
12-23 12:23:53.134: WARN/dalvikvm(3067): threadid=46: thread exiting with uncaught exception (group=0x400259f8)
12-23 12:23:53.134: ERROR/AndroidRuntime(3067): FATAL EXCEPTION: Thread-1016
12-23 12:23:53.134: ERROR/AndroidRuntime(3067): java.lang.OutOfMemoryError: bitmap size exceeds VM budget
12-23 12:23:53.134: ERROR/AndroidRuntime(3067): at android.graphics.BitmapFactory.nativeDecodeStream(Native Method)
12-23 12:23:53.134: ERROR/AndroidRuntime(3067): at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:468)
12-23 12:23:53.134: ERROR/AndroidRuntime(3067): at android.graphics.BitmapFactory.decodeResourceStream(BitmapFactory.java:332)
12-23 12:23:53.134: ERROR/AndroidRuntime(3067): at android.graphics.drawable.Drawable.createFromResourceStream(Drawable.java:697)
12-23 12:23:53.134: ERROR/AndroidRuntime(3067): at android.graphics.drawable.Drawable.createFromStream(Drawable.java:657)
12-23 12:23:53.134: ERROR/AndroidRuntime(3067): at com.nbcu.myApp.appsupport.AsyncImageLoader.loadImageFromUrl(AsyncImageLoader.java:98)
12-23 12:23:53.134: ERROR/AndroidRuntime(3067): at com.nbcu.myApp.appsupport.AsyncImageLoader$2.run(AsyncImageLoader.java:70)
12-23 12:23:53.154: WARN/ActivityManager(96): Force finishing activity com.nbcu.myApp.activities/com.nbcu.myApp.controllers.StoriesListController
12-23 12:23:53.224: ERROR/dalvikvm-heap(3067): 45850-byte external allocation too large for this process.
12-23 12:23:53.234: DEBUG/SurfaceFlinger(96): Layer::setBuffers(this=0x2fabc0), pid=96, w=1, h=1
12-23 12:23:53.234: ERROR/dalvikvm(3067): Out of memory: Heap Size=13127KB, Allocated=11948KB, Bitmap Size=11407KB
12-23 12:23:53.234: ERROR/GraphicsJNI(3067): VM won't let us allocate 45850 bytes
12-23 12:23:53.234: ERROR/Error(3067): Message = java.lang.OutOfMemoryError: bitmap size exceeds VM budget
The code where images are being downloaded is:
public void run() {
Looper.prepare();
for (int i = 0; i < slides.size(); i++) {
try {
final SlideShowItem story = slides.get(i);
if (story.getImage() == null) {
Drawable cachedImage = Utils.database.getRSSImage(Constants.StoriesTable, story.getItemId());
if (cachedImage != null) {
story.setImage(cachedImage);
} else {
cachedImage = asyncImageLoader.loadDrawable(story.getImagePath(), new ImageCallback() {
public void imageLoaded(Drawable imageDrawable, String imageUrl) {
story.setImage(imageDrawable);
Utils.database.storeRSSItemImage(Constants.StoriesTable, imageDrawable, story.getItemId());
}
});
}
}
Thread.sleep(500);
} catch (Exception e) {
e.printStackTrace();
}
}
Looper.loop();
}
Code for loadDrawable() is:
public Drawable loadDrawable(final String imageUrl, final ImageCallback imageCallback) {
final Handler handler = new Handler() {
public void handleMessage(Message message) {
imageCallback.imageLoaded((Drawable) message.obj, imageUrl);
}
};
new Thread() {
public void run() {
Drawable drawable = loadImageFromUrl(imageUrl);
// System.out.println("image url: " + imageUrl);
if (drawable != null)
{
Message message = handler.obtainMessage(0, drawable);
handler.sendMessage(message);
}
}
}.start();
return null;
}
and the code for loadImageFromURL() is:
public static Drawable loadImageFromUrl(String url) {
Drawable image = null;
try {
InputStream in = (java.io.InputStream) new java.net.URL(url).getContent();
if (in != null) {
image = Drawable.createFromStream(in, "image");
}
in.close();
} catch (Exception ex) {
// ex.printStackTrace();
Log.v("Exception ", "Asyn Image.In LoadImageFromURL Message: " + ex.toString());
}
return image;
}
Once images are downloaded they are cached. I am unable to find a workaround to avoid this exception. what could be the reason? I have also tried setting image views null when activity is destroyed but it has done nothing for me? Any help is appreciated. Thanks in advance.
Upvotes: 4
Views: 1468
Reputation: 8380
Consider downscaling the cached images to the size of the views they are used with. For example you may use following approach in your loadImageFromUrl(String url)
method:
// Determining the original size of the image:
BitmapFactory.Options optnsSizeOnly = new BitmapFactory.Options();
optnsSizeOnly.inJustDecodeBounds = true;
InputStream inputStreamSizeOnly = (java.io.InputStream) new java.net.URL(url).getContent();
BitmapFactory.decodeStream(inputStreamSizeOnly, null, optnsSizeOnly);
int widthOriginal = optnsSizeOnly.outWidth;
// Determining the scale ratio.
// Note, it's just an example, you should use more sophisticated algorithm:
int ratio = widhtOriginal / widthView; // widthView is supposed to be known
// Now loading the scaled image:
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = ratio;
InputStream inputStream = (java.io.InputStream) new java.net.URL(url).getContent();
Bitmap bitmap = BitmapFactory.decodeStream(inputStream, null, options);
Upvotes: 4
Reputation: 21409
You should use a kind of tweaked lazy initialization . I would go for using 3 images at a time, the image currently displayed and the next two. This way, when the user is viewing image1, image2 and image3 are already in memory. When user slides to image2, image4 should be loaded into the previous image1 buffer (image3 is still in memory) I hope this helps
Upvotes: 2
Reputation: 11930
Android is a Mobile OS. It has a limited memory, so, you cannot cache all the slides.size(). I assume the size > 15. For example, im running a FastCV algorithm with a HD image as markers, 250000 x 180000 pixels and if i run the program on pc, work fine, if i do it on the mobile phone dont, because the memory is not enough.
I think you can solve the problem, if only caché 10 - 15 images, depends the size of them. If scroll, then cache new one in the memory already used.
Upvotes: 5