I'm new in Android programming and I got an error that says that my app run out of memory, this exampled I copied from a book and it is working with small pictures resolution, but when I added a few pictures with a bigger resolution out of memory error appears, may be I do something wrong or just don't know all I should yet to work with images, if anyone know what should i change so that this error won't appear again, pleas help. Thank you anticipate!
The source code:
public class ImageViewsActivity extends Activity {
//the images to display
Integer[] imageIDs={
R.drawable.pic1,
R.drawable.pic2,
R.drawable.pic3,
R.drawable.pic4,
R.drawable.pic5
};
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
final ImageView iv=(ImageView) findViewById(R.id.image1);
Gallery gallery=(Gallery) findViewById(R.id.gallery);
gallery.setAdapter(new ImageAdapter(this));
gallery.setOnItemClickListener(new OnItemClickListener(){
public void onItemClick(AdapterView<?> parent, View v, int position, long id){
Toast.makeText(getBaseContext(), "pic"+(position+1)+" selected", Toast.LENGTH_SHORT).show();
//display the image selected
try{iv.setScaleType(ImageView.ScaleType.FIT_CENTER);
iv.setImageResource(imageIDs[position]);}catch(OutOfMemoryError e){
iv.setImageBitmap(null);
}
}
});
}
public class ImageAdapter extends BaseAdapter{
private Context context;
private int itemBackground;
public ImageAdapter(Context c){
context=c;
//setting the style
TypedArray a = obtainStyledAttributes(R.styleable.Gallery1);
itemBackground = a.getResourceId(R.styleable.Gallery1_android_galleryItemBackground, 0);
a.recycle();
}
//returns the number of images
public int getCount() {
// TODO Auto-generated method stub
return imageIDs.length;
}
//returns the ID of an item
public Object getItem(int position) {
// TODO Auto-generated method stub
return position;
}
//returns the ID of an item
public long getItemId(int position) {
// TODO Auto-generated method stub
return position;
}
//returns an ImageView view
public View getView(int position, View convertView, ViewGroup parent) {
// TODO Auto-generated method stub
ImageView iv= new ImageView(context);
iv.setImageResource(imageIDs[position]);
iv.setScaleType(ImageView.ScaleType.FIT_XY);
iv.setLayoutParams(new Gallery.LayoutParams(150,120));
iv.setBackgroundResource(itemBackground);
return iv;
}
}}
ERROR HERE:
04-18 10:38:31.661: D/dalvikvm(10152): Debugger has detached; object registry had 442 entries
04-18 10:38:31.661: D/AndroidRuntime(10152): Shutting down VM
04-18 10:38:31.661: W/dalvikvm(10152): threadid=1: thread exiting with uncaught exception (group=0x4001d820)
04-18 10:38:31.691: E/AndroidRuntime(10152): FATAL EXCEPTION: main
04-18 10:38:31.691: E/AndroidRuntime(10152): java.lang.OutOfMemoryError: bitmap size exceeds VM budget
04-18 10:38:31.691: E/AndroidRuntime(10152): at android.graphics.Bitmap.nativeCreate(Native Method)
04-18 10:38:31.691: E/AndroidRuntime(10152): at android.graphics.Bitmap.createBitmap(Bitmap.java:499)
04-18 10:38:31.691: E/AndroidRuntime(10152): at android.graphics.Bitmap.createBitmap(Bitmap.java:466)
04-18 10:38:31.691: E/AndroidRuntime(10152): at android.graphics.Bitmap.createScaledBitmap(Bitmap.java:371)
04-18 10:38:31.691: E/AndroidRuntime(10152): at android.graphics.BitmapFactory.finishDecode(BitmapFactory.java:539)
04-18 10:38:31.691: E/AndroidRuntime(10152): at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:508)
04-18 10:38:31.691: E/AndroidRuntime(10152): at android.graphics.BitmapFactory.decodeResourceStream(BitmapFactory.java:365)
04-18 10:38:31.691: E/AndroidRuntime(10152): at android.graphics.drawable.Drawable.createFromResourceStream(Drawable.java:728)
04-18 10:38:31.691: E/AndroidRuntime(10152): at android.content.res.Resources.loadDrawable(Resources.java:1740)
04-18 10:38:31.691: E/AndroidRuntime(10152): at android.content.res.Resources.getDrawable(Resources.java:612)
04-18 10:38:31.691: E/AndroidRuntime(10152): at android.widget.ImageView.resolveUri(ImageView.java:520)
04-18 10:38:31.691: E/AndroidRuntime(10152): at android.widget.ImageView.setImageResource(ImageView.java:305)
04-18 10:38:31.691: E/AndroidRuntime(10152): at image.view.GalleryView$ImageAdapter.getView(GalleryView.java:95)
04-18 10:38:31.691: E/AndroidRuntime(10152): at android.widget.Gallery.makeAndAddView(Gallery.java:776)
04-18 10:38:31.691: E/AndroidRuntime(10152): at android.widget.Gallery.fillToGalleryLeft(Gallery.java:695)
04-18 10:38:31.691: E/AndroidRuntime(10152): at android.widget.Gallery.trackMotionScroll(Gallery.java:406)
04-18 10:38:31.691: E/AndroidRuntime(10152): at android.widget.Gallery$FlingRunnable.run(Gallery.java:1397)
04-18 10:38:31.691: E/AndroidRuntime(10152): at android.os.Handler.handleCallback(Handler.java:618)
04-18 10:38:31.691: E/AndroidRuntime(10152): at android.os.Handler.dispatchMessage(Handler.java:123)
04-18 10:38:31.691: E/AndroidRuntime(10152): at android.os.Looper.loop(Looper.java:154)
04-18 10:38:31.691: E/AndroidRuntime(10152): at android.app.ActivityThread.main(ActivityThread.java:4668)
04-18 10:38:31.691: E/AndroidRuntime(10152): at java.lang.reflect.Method.invokeNative(Native Method)
04-18 10:38:31.691: E/AndroidRuntime(10152): at java.lang.reflect.Method.invoke(Method.java:552)
04-18 10:38:31.691: E/AndroidRuntime(10152): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:917)
04-18 10:38:31.691: E/AndroidRuntime(10152): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:674)
04-18 10:38:31.691: E/AndroidRuntime(10152): at dalvik.system.NativeStart.main(Native Method)
To add on Ken's answer, which is a solid piece of code, I thought I'd knock it down after he set it up:
if(imageView != null) {
((BitmapDrawable)imageView.getDrawable()).getBitmap().recycle();
}
imageView = (ImageView) view.findViewById(R.id.imageView);
imageView.setImageResource(resID);
NOTE: This won't work if you are trying to swap an image you already recycled. You'll get something like this in LOGCAT
Canvas: trying to use a recycled bitmap
So what I do now if I don't have to load a bunch of different images asynchronously, I simply put this in onDestroy when dealing with fragments and large background images:
@Override
public void onDestroy() {
super.onDestroy();
imageView.setImageDrawable(null);
}
For those using the Glide image loading library, who are still running into these OutOfMemory Exception
issues, there're many things you can do to make Glide
use less memory and hopefully fix your problem. Here are a few of them:
Don't use android:scaleType="fitXY"
inside of your ImageView
. So if you're ImageView
looks like this:
<ImageView android:id="@android:id/icon"
android:layout_width="@dimen/width"
android:layout_height="@dimen/height"
android:adjustViewBounds="true"
android:scaleType="fitXY"
<!-- DON'T USE "fitXY"! -->
/>
Change the ImageView
to use a different android:scaleType
, preferably: fitCenter
or centerCrop
.
wrap_content
in your ImageView
, instead use match_parent
or specify the width
/height
explicitly using a size in dp
. If you really insist on using wrap_content
in your ImageView
, at least set a android:maxHeight
/android:maxWidth
.dontAnimate()
on your Glide.with()...
request.If you're loading lots of potentially large images (as you would in a list/grid), specify a thumbnail(float sizeMultiplier)
load in your request. Ex:
Glide.with(context)
.load(imageUri)
.thumbnail(0.5f)
.dontAnimate()
.into(iconImageView);
Temporarily lower Glide
's memory footprint during certain phases of your app by using: Glide.get(context).setMemoryCategory(MemoryCategory.LOW)
.
skipMemoryCache(true)
on your Glide.with()...
request. This will still cache the images to disk, which you'll probably want since you're foregoing the in-memory cache.Drawable
from your local resources, make sure that the image you're trying to load ISN'T SUPER HUGE. There are plenty of image compression tools available online. These tools will shrink the sizes of your images while also maintaining their appearance quality. .diskCacheStrategy(DiskCacheStrategy.NONE)
.Hook into the onTrimMemory(int level)
callback that Android provides to trim the Glide
cache as needed. Ex.
@Override
public void onTrimMemory(int level)
{
super.onTrimMemory(level);
Glide.get(this).trimMemory(level);
}
If displaying images in a RecyclerView
you can explicitly clear Glide
when views are recycled, like so:
@Override
public void onViewRecycled(MyAdapter.MyViewHolder holder)
{
super.onViewRecycled(holder);
Glide.clear(holder.imageView);
}
Glide
is just the one thing that's pushing it to the OutOfMemory Exception
zone... So be sure you don't have any memory leaks in your application. Android Studio
provides tools for identifying memory consumption issues in you app.If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With