GVillani82
GVillani82

Reputation: 17429

OutOfMemoryError using ArrayAdapter in ListView

I created a ListView using an ArrayAdapter that implements the getView() method in this way:

public View getView(int position, View convertView, ViewGroup parent) {
    View rowView = convertView;
    if(rowView ==null){
    LayoutInflater inflater = (LayoutInflater) context
                    .getSystemService(Context.LAYOUT_INFLATER_SERVICE);         
    rowView = inflater.inflate(R.layout.rowlayout_member, parent, false);
            }
    TextView textView = (TextView) rowView.findViewById(R.id.label);
    TextView textView1 = (TextView) rowView.findViewById(R.id.label1);
    ImageView imageView = (ImageView) rowView.findViewById(R.id.icon);
    textView.setText(values[position]);
    textView1.setText(surname[position]);

    String s = values[position];
    if(foto[position] != null){
    Drawable c = Drawable.createFromPath(basePath+foto[position]);   // line 56 
    if(c!=null)
        imageView.setImageDrawable(c);
    else
        imageView.setImageResource(R.drawable.default);
    }else{
        imageView.setImageResource(R.drawable.default);                
    }
    return rowView;
}

All seems to work fine, but when I come in and go out to the List for many times(changing Activity) sometimes I obtain the following error:

08-06 15:06:14.110: E/dalvikvm-heap(3527): Out of memory on a 2380816-byte allocation.
08-06 15:06:14.110: W/dalvikvm(3527): threadid=1: thread exiting with uncaught exception (group=0x40a3d1f8)
08-06 15:06:14.120: E/AndroidRuntime(3527): FATAL EXCEPTION: main
08-06 15:06:14.120: E/AndroidRuntime(3527): java.lang.OutOfMemoryError
08-06 15:06:14.120: E/AndroidRuntime(3527):     at android.graphics.BitmapFactory.nativeDecodeStream(Native Method)
08-06 15:06:14.120: E/AndroidRuntime(3527):     at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:493)
08-06 15:06:14.120: E/AndroidRuntime(3527):     at android.graphics.BitmapFactory.decodeFile(BitmapFactory.java:299)
08-06 15:06:14.120: E/AndroidRuntime(3527):     at android.graphics.BitmapFactory.decodeFile(BitmapFactory.java:324)
08-06 15:06:14.120: E/AndroidRuntime(3527):     at android.graphics.drawable.Drawable.createFromPath(Drawable.java:880)
08-06 15:06:14.120: E/AndroidRuntime(3527):     at host.framework.component.MySimpleArrayAdapter.getView(MySimpleArrayAdapter.java:56)
08-06 15:06:14.120: E/AndroidRuntime(3527):     at android.widget.AbsListView.obtainView(AbsListView.java:2012)
08-06 15:06:14.120: E/AndroidRuntime(3527):     at android.widget.ListView.makeAndAddView(ListView.java:1772)
08-06 15:06:14.120: E/AndroidRuntime(3527):     at android.widget.ListView.fillUp(ListView.java:705)
08-06 15:06:14.120: E/AndroidRuntime(3527):     at android.widget.ListView.fillGap(ListView.java:645)
08-06 15:06:14.120: E/AndroidRuntime(3527):     at android.widget.AbsListView.trackMotionScroll(AbsListView.java:4546)
08-06 15:06:14.120: E/AndroidRuntime(3527):     at android.widget.AbsListView$FlingRunnable.run(AbsListView.java:3813)
08-06 15:06:14.120: E/AndroidRuntime(3527):     at android.os.Handler.handleCallback(Handler.java:605)
08-06 15:06:14.120: E/AndroidRuntime(3527):     at android.os.Handler.dispatchMessage(Handler.java:92)
08-06 15:06:14.120: E/AndroidRuntime(3527):     at android.os.Looper.loop(Looper.java:137)
08-06 15:06:14.120: E/AndroidRuntime(3527):     at android.app.ActivityThread.main(ActivityThread.java:4424)
08-06 15:06:14.120: E/AndroidRuntime(3527):     at java.lang.reflect.Method.invokeNative(Native Method)
08-06 15:06:14.120: E/AndroidRuntime(3527):     at java.lang.reflect.Method.invoke(Method.java:511)
08-06 15:06:14.120: E/AndroidRuntime(3527):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:784)
08-06 15:06:14.120: E/AndroidRuntime(3527):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:551)
08-06 15:06:14.120: E/AndroidRuntime(3527):     at dalvik.system.NativeStart.main(Native Method)
08-06 15:06:14.120: W/ActivityManager(149):   Force finishing activity host.activity/.ACT_CircoliDiSupporto
08-06 15:06:14.640: W/ActivityManager(149): Activity pause timeout for ActivityRecord{413de508 host.activity/.ACT_CircoliDiSupporto}
08-06 15:06:24.140: W/ActivityManager(149): Launch timeout has expired, giving up wake lock!
08-06 15:06:24.650: W/ActivityManager(149): Activity idle timeout for ActivityRecord{41389d58 host.activity/.HostActivity}

The line 56 (highlighted in the code) seems to generate the error

Drawable c = Drawable.createFromPath(basePath+foto[position]); 

Upvotes: 3

Views: 1475

Answers (2)

Kai
Kai

Reputation: 15476

There are a number of problems with the current implementation:

  1. The code accesses and builds a Bitmap on the main/UI thread (Drawable c = Drawable.createFromPath(basePath+foto[position]); // line 56), this would make your list scrolling quite choppy
  2. A new drawable is created each time a view is requested, on 2.x Android systems it'll take a while for an unreferenced Bitmap to be collected by the Garbage Collector (GC), exacerbating the memory issue
  3. You load the image from storage without scaling it to the proper size, this may or may not be an issue since I don't know the dimension of the image you are displaying nor the dimension of the images

I would suggest you to use Universal Image Loader library (https://github.com/nostra13/Android-Universal-Image-Loader) which would solve all of the above issues. Though I am not sure if it provides native local image loading capability or if you have to extend some class to have such a capability.


[Edit]

I wouldn't recommend rolling your own solution as it'll take more time than you'd first imagined (trust me...). But if you really want to do it you can check out this tutorial: http://codehenge.net/blog/2011/06/android-development-tutorial-asynchronous-lazy-loading-and-caching-of-listview-images/

The above tutorial solves #1 & #2, for #3 check this: Strange out of memory issue while loading an image to a Bitmap object

Upvotes: 3

AjOnFire
AjOnFire

Reputation: 2878

First of all you need a data structure like LruCache to hold the drawables that are being created.

How can I be sure that my objects are correctly released?

On activity destroy with usage the data structure, make sure the object of the class is being made null or clearing internal objects of it. (This will tell the gc that this object is ready to be cleared (in most cases)).

Also running a file operation on main thread is not the best approach as it will introduce jerkiness in listview scrolling. Try to do this in secondary thread.

Upvotes: 1

Related Questions