3

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]); 
2
  • 1
    Are you properly releasing the objects? Do not create drawables inside getView()... at least create it only once and re use that objects later on. Commented Aug 6, 2013 at 14:00
  • How can I be sure that my objects are correctly released? Uhm, maybe you are right: each time the getView is called a new Drawable is created. Commented Aug 6, 2013 at 14:04

2 Answers 2

3

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

Sign up to request clarification or add additional context in comments.

7 Comments

Yes, you are right @Kai, my List is pretty choppy. Supposing I don't want use the Universal Loader library how can I deal with the problems you listed above? I suppose: 1) Create a separate thread that shold be interrupted if the item comes out of the scope of the list? 2) I can create a bitmap once, outside of getView? 3) I can scale all the image properly? Can this be acceptable?
@Joseph82 updated answer, note that even the tutorial isn't really doing it right as it doesn't cancel the view's previous retrieve image operation, which would lead to "flashing image" artifects when scrolling very fast. So again I don't personally recommend this :P
Thank you @Kai. I think at first I'll try my solution: I like challenges :) But then I thin I will use the library that you suggest xD
Good call. I was using my own AsyncTask to implement these functions, but had to fight a lot of bugs related to download-task-canceling and other issues until I realized now there are amazing image loading libs with less bugs and better functions. Certainly taught me a lesson on continuously checking the great StackOverflow for new libs/implementations/ideas.
Yes, surely it can be an opportunity to learn more about the Android world :)
|
1

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.

2 Comments

Thank you @66CLSjY can you give me some example of how to use LruCache in ListView?
Check out stackoverflow.com/questions/11623994/… and also research on Bitmap.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.