Reputation: 157
I cannot seem to figure out why my activity keeps running out of memory.
When I load my activity, I have a bunch of images that are loaded into a custom listview adapter. When I start the activity, the screen loads fine. But when I change orientation or go back and start it again, the activity generates an Out of Memory Exception.
Here's what my activity looks like:
Here's the code for my activity:
[Activity(Label = "FishinTales: Fish Species")]
public class Activity_View_FishSpecies : Activity
{
#region Components
private Model n_model;
private ListView n_fishSpeciesListView;
#endregion
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
// Get Application Global Model
this.n_model = ((MyApp) this.ApplicationContext).FishingData;
// Set our view from the "View_FishSpecies" layout resource
SetContentView(Resource.Layout.View_FishSpecies);
this.n_fishSpeciesListView = FindViewById<ListView> (Resource.Id.xml_fishSpeciesListView);
this.n_fishSpeciesListView.Adapter = new FishSpeciesListAdapter (this.ApplicationContext, this.n_model.SpecieManager.Species);
}
protected override void OnDestroy()
{
base.OnDestroy();
this.unbindDrawables(FindViewById(Resource.Id.xml_root));
this.n_fishSpeciesListView.Adapter = null;
this.n_fishSpeciesListView = null;
}
private void unbindDrawables(View view) {
if (view.Background != null) {
view.Background.SetCallback(null);
}
if (view.GetType() == typeof(ViewGroup)) {
for (int i = 0; i < ((ViewGroup) view).ChildCount; i++) {
unbindDrawables(((ViewGroup) view).GetChildAt(i));
}
((ViewGroup) view).RemoveAllViews();
}
}
}
public class FishSpeciesListAdapter : BaseAdapter
{
Context n_context;
List<AppCode.Specie> n_specieData;
List<Bitmap> n_bitmapCache;
public FishSpeciesListAdapter (Context context, List<AppCode.Specie> specieData)
{
this.n_context = context;
this.n_specieData = specieData;
this.n_bitmapCache = new List<Bitmap>();
this.LoadBitmapsIntoCache();
}
private void LoadBitmapsIntoCache()
{
foreach(AppCode.Specie specie in this.n_specieData)
{
if (specie.RelatedMedia.AttachedPhotos.Count < 1)
{
this.n_bitmapCache.Add(BitmapFactory.DecodeResource(this.n_context.Resources, Resource.Drawable.Icon));
}
else
{
this.n_bitmapCache.Add(BitmapFactory.DecodeByteArray(specie.RelatedMedia.AttachedPhotos[0], 0, specie.RelatedMedia.AttachedPhotos[0].Length));
}
}
}
public override int Count {
get { return this.n_specieData.Count; }
}
public override Java.Lang.Object GetItem (int position)
{
return null;
}
public override long GetItemId (int position)
{
return 0;
}
// create a new ImageView for each item referenced by the Adapter
public override View GetView (int position, View convertView, ViewGroup parent)
{
if(convertView==null){
LayoutInflater li = LayoutInflater.FromContext(parent.Context);
convertView = li.Inflate(Resource.Layout.Adapter_FishSpeciesIcon, null);
}
ImageView iconImage = (ImageView)convertView.FindViewById(Resource.Id.xml_adapter_fishSpeciesIconImage);
TextView nameText = (TextView)convertView.FindViewById(Resource.Id.xml_adapter_fishSpeciesNameText);
TextView scientificNameText = (TextView)convertView.FindViewById(Resource.Id.xml_adapter_fishSpeciesScientificNameText);
nameText.Text = this.n_specieData[position].Name;
scientificNameText.Text = this.n_specieData[position].ScientificName;
iconImage.SetImageBitmap(this.n_bitmapCache[position]);
return convertView;
}
}
Here's my log of all processes until the OOM error is generated.
Loading Defaults - Successfully Loaded Defaults
Grow heap (frag case) to 6.474MB for 314670-byte allocation
Clamp target GC heap from 32.512MB to 32.000MB
796824-byte external allocation too large for this process.
VM won't let us allocate 796824 bytes
Clamp target GC heap from 33.447MB to 32.000MB
--- decoder->decode returned false
UNHANDLED EXCEPTION: Java.Lang.OutOfMemoryError: Exception of type 'Java.Lang.OutOfMemoryError' was thrown.
at Android.Runtime.JNIEnv.CallStaticObjectMethod (intptr,intptr,Android.Runtime.JValue[]) <0x00080>
at Android.Graphics.BitmapFactory.DecodeByteArray (byte[],int,int) <0x001bb>
at FishinTales.FishSpeciesListAdapter.LoadBitmapsIntoCache () <0x00187>
at FishinTales.FishSpeciesListAdapter..ctor (Android.Content.Context,System.Collections.Generic.List`1<FishinTales.AppCode.Specie>) <0x000a3>
at FishinTales.Activity_View_FishSpecies.OnCreate (Android.OS.Bundle) <0x0012f>
at Android.App.Activity.n_OnCreate_Landroid_os_Bundle_ (intptr,intptr,intptr) <0x00057>
at (wrapper dynamic-method) object.99ebf5db-74ad-4da9-b431-612691e1f213 (intptr,intptr,intptr) <0x00033>
--- End of managed exception stack trace ---
java.lang.OutOfMemoryError: bitmap size exceeds VM budget(Heap Size=6855KB, Allocated=3089KB, Bitmap Size=26666KB)
at android.graphics.BitmapFactory.nativeDecodeByteArray(Native Method)
at android.graphics.BitmapFactory.decodeByteArray(BitmapFactory.java:625)
at android.graphics.BitmapFactory.decodeByteArray(BitmapFactory.java:638)
at fishintales.Activity_View_FishSpecies.n_onCreate(Native Method)
at fishintales.Activity_View_FishSpecies.onCreate(Activity_View_FishSpecies.java:29)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1093)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1780)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:1837)
at android.app.ActivityThread.handleRelaunchActivity(ActivityThread.java:3242)
at android.app.ActivityThread.access$1600(ActivityThread.java:132)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1037)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:143)
at android.app.ActivityThread.main(ActivityThread.java:4196)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:507)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:839)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:597)
at dalvik.system.NativeStart.main(Native Method)
Unhandled Exception:
Java.Lang.OutOfMemoryError: Exception of type 'Java.Lang.OutOfMemoryError' was thrown.
at Android.Runtime.JNIEnv.CallStaticObjectMethod (intptr,intptr,Android.Runtime.JValue[]) <0x00080>
at Android.Graphics.BitmapFactory.DecodeByteArray (byte[],int,int) <0x001bb>
at FishinTales.FishSpeciesListAdapter.LoadBitmapsIntoCache () <0x00187>
at FishinTales.FishSpeciesListAdapter..ctor (Android.Content.Context,System.Collections.Generic.List`1<FishinTales.AppCode.Specie>) <0x000a3>
at FishinTales.Activity_View_FishSpecies.OnCreate (Android.OS.Bundle) <0x0012f>
at Android.App.Activity.n_OnCreate_Landroid_os_Bundle_ (intptr,intptr,intptr) <0x00057>
at (wrapper dynamic-method) object.99ebf5db-74ad-4da9-b431-612691e1f213 (intptr,intptr,intptr) <0x00033>
--- End of managed exception stack trace ---
java.lang.OutOfMemoryError: bitmap size exceeds VM budget(Heap Size=6855KB, Allocated=3089KB, Bitmap Size=26666KB)
at android.graphics.BitmapFactory.nativeDecodeByteArray(Native Method)
at android.gra
When I view the activity initially, everything is fine. When I leave the activity and come back to it several times, it eventually crashes with the above error. This leads me to speculate that the error is coming from a memory leak where the Bitmaps are not recycled properly. So is there any example out there of how to deallocate these bitmaps acurately? It's hard to find information on this topic when your Bitmaps are inside the Custom ListView Adapter class. When I put Bitmap.recycle after I set it, I receive yet another error that says that the ListView is trying to access a recycled item. So how/when should I recycle according to the code above.
Upvotes: 2
Views: 2960
Reputation: 1946
I would like to know which version of Android you are using. If it is Jelly Bean (Android 4.1.1) please remove this line of code
this.n_bitmapCache.Add(BitmapFactory.DecodeResource(this.n_context.Resources, Resource.Drawable.Icon));
and see whether you are getting memory leak.
My app also started giving memory leak after an update to Android 4.1.1 and I found the problem to be in
setBackgroundResource(id);
I tried changing it to
setBackground(context.getResources().getDrawable(id));
But still was getting the memory leak. I want to confirm if it is a bug in my code or bug in Jelly Bean which is causing a memory leak if we try to create drawables or bitmaps from Resources. Apologies for not answering your question but we can at least know the cause of the bug and raise an issue with the Android team.
UPDATE I found the solution in this link
Please use setBackgroundDrawable(null) for the Bitmaps created from the drawable folder of resources.
Upvotes: 1