I have a simple gridview that shows bitmaps. The view is very jenky due to the garbage collection. I have come experience with garbage collection in listviews and have a fairly heavy weight one running smoothly. However I cannot understand what is happening here. The UI thread is blocked so much when I fling the view. The stack traces looks like so
12-20 13:22:46.187: D/dalvikvm(17979): WAIT_FOR_CONCURRENT_GC blocked 106ms 12-20 13:22:46.187: D/dalvikvm(17979): WAIT_FOR_CONCURRENT_GC blocked 106ms 12-20 13:22:46.187: D/dalvikvm(17979): WAIT_FOR_CONCURRENT_GC blocked 106ms 12-20 13:22:46.187: D/dalvikvm(17979): WAIT_FOR_CONCURRENT_GC blocked 106ms 12-20 13:22:46.187: D/dalvikvm(17979): WAIT_FOR_CONCURRENT_GC blocked 107ms 12-20 13:22:46.187: D/dalvikvm(17979): WAIT_FOR_CONCURRENT_GC blocked 107ms 12-20 13:22:46.191: D/dalvikvm(17979): WAIT_FOR_CONCURRENT_GC blocked 108ms 12-20 13:22:46.191: D/dalvikvm(17979): WAIT_FOR_CONCURRENT_GC blocked 108ms 12-20 13:22:46.191: D/dalvikvm(17979): WAIT_FOR_CONCURRENT_GC blocked 109ms 12-20 13:22:46.191: D/dalvikvm(17979): WAIT_FOR_CONCURRENT_GC blocked 108ms 12-20 13:22:46.191: D/dalvikvm(17979): WAIT_FOR_CONCURRENT_GC blocked 108ms 12-20 13:22:46.191: D/dalvikvm(17979): WAIT_FOR_CONCURRENT_GC blocked 109ms 12-20 13:22:46.191: D/dalvikvm(17979): WAIT_FOR_CONCURRENT_GC blocked 109ms 12-20 13:22:46.191: D/dalvikvm(17979): WAIT_FOR_CONCURRENT_GC blocked 110ms 12-20 13:22:46.195: D/dalvikvm(17979): WAIT_FOR_CONCURRENT_GC blocked 111ms 12-20 13:22:46.195: D/dalvikvm(17979): WAIT_FOR_CONCURRENT_GC blocked 110ms 12-20 13:22:46.195: D/dalvikvm(17979): WAIT_FOR_CONCURRENT_GC blocked 111ms 12-20 13:22:46.195: D/dalvikvm(17979): WAIT_FOR_CONCURRENT_GC blocked 110ms 12-20 13:22:46.195: D/dalvikvm(17979): WAIT_FOR_CONCURRENT_GC blocked 114ms
The adapter I am using is like this....
public class PhotoSelectorAdapter extends BaseAdapter {
private Context context;
private String[] paths;
private final Executor executor = Executors.newFixedThreadPool(20);
public PhotoSelectorAdapter(Context context, String[] paths) {
this.context = context;
this.paths = paths;
}
public int getCount() {
return paths.length;
}
public Object getItem(int position) {
return null;
}
public long getItemId(int position) {
return 0;
}
public View getView(int position, View convertView, ViewGroup parent) {
ImageView imageView;
ImageGetter imageGetter;
if (convertView == null) {
imageView = new ImageView(context);
imageView.setLayoutParams(new GridView.LayoutParams(150, 150));
imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
imageView.setPadding(8, 8, 8, 8);
} else {
imageView = (ImageView) convertView;
imageView.setImageBitmap(null);
imageGetter = (ImageGetter) imageView.getTag();
if (imageGetter != null) {
imageGetter.cancel(true);
}
}
imageGetter = new ImageGetter(context, paths[position], imageView);
executor.execute(imageGetter.future());
imageView.setTag(imageGetter);
return imageView;
}
class ImageGetter extends RoboAsyncTask<Bitmap> {
private WeakReference<ImageView> imageViewReference;
private String path;
BitmapFactory.Options options = new BitmapFactory.Options();
protected ImageGetter(Context context, String path, ImageView imageView) {
super(context);
this.path = path;
this.imageViewReference = new WeakReference<ImageView>(imageView);
}
@Override
public Bitmap call() throws Exception {
options.inSampleSize = 10;
return BitmapFactory.decodeFile(path, options);
}
@Override
protected void onSuccess(Bitmap bitmap) throws Exception {
super.onSuccess(bitmap);
if (future.isCancelled()) {
bitmap = null;
} else {
if (imageViewReference != null) {
ImageView imageView = imageViewReference.get();
if (imageView != null) {
imageView.setImageBitmap(bitmap);
}
}
}
}
}
The steps that I have taken to avoid garbage collection is
- taking a sample size of 10 for the bitmap
- canceling a task if it is not needed anymore in the hope of not creating unnecessary bitmaps
What is going on?