Question

I'm building a Pulse kind of UI. For this I'm using Gallery inside ListView. However, I'm facing a strange issue, the memory allocation in my app increases gradually from 9 MB to 64 MB as I scroll through listview until which it finally crashes.

What didn't work:

  • I doubted if this is because of bitmaps that I'm using. So, I tested it without images inside gallery. I also used Universal Image Loader library. However, nothing changed.

  • I read on similar question in SO that disabling scrollingCache of listView might help. However, still no effect.

What worked:

  • Designing efficient adapter using ViewHolder, getTag(), setTag() solved memory issues. However, it brought a strange issue that the listView sometimes shows empty or repeating rows, thereby showing wrong data in UI. How can I solve this? Is there any better approach to go about this?

ListViewAdapter.java

public class ListViewAdapter extends BaseAdapter {
    String user_locale;
    Context context;
    LayoutInflater inflater;
    AssetsAdapter assestsAdapter;
    List<Category> categoryList;
    List<BaseAssets> baseAssetList;
    AssetsTable assetTable;
    ViewHolder viewHolder;

public ListViewAdapter(Context context, List<Category> categoryList) {
    this.context = context;
    user_locale = Universal.getCurrentLanguage(context);
    inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    this.categoryList = categoryList;
    assetTable = new AssetsTable(context);
    viewHolder = new ViewHolder();
}

public int getCount() {
    return categoryList.size();
}

public Object getItem(int position) {
    return position;
}

public long getItemId(int position) {
    return position;
}

public View getView(final int position, View convertView, ViewGroup parent) {
    String catID = categoryList.get(position).catID;

    if (convertView == null)
    {
        convertView = inflater.inflate(R.layout.category_list_item, parent, false);
        viewHolder.categoryTitle = (TextView) convertView.findViewById(R.id.category_title);
        viewHolder.gallery = (Gallery) convertView.findViewById(R.id.gallery);
        convertView.setTag(viewHolder);
    } else
        viewHolder = (ViewHolder) convertView.getTag();

    assetTable = new AssetsTable(context);
    int count = assetTable.getCountOfParticularCategory(catID);

    initializeGallery(catID);

    String text = categoryList.get(position).catName + "  (" + count + ")  ";
    viewHolder.categoryTitle.setText(text);
    return convertView;

}

public void initializeGallery(String catID) {
    assetTable = new AssetsTable(context);
    baseAssetList = assetTable.getAllBaseAssets(catID);
    assestsAdapter = new AssetsAdapter(context, baseAssetList);
    adjustGalleryHeight();
    viewHolder.gallery.setAdapter(assestsAdapter);
}

public void adjustGalleryHeight() {
    boolean isPortrait = false;
    final String TAG_PORTRAIT = "portrait";

    for (BaseAssets b : baseAssetList)
    {
        if (b.thumbOrientation.equals(TAG_PORTRAIT))
            isPortrait = true;
    }

    final float scale = context.getResources().getDisplayMetrics().density;
    if (isPortrait)
    {
        RelativeLayout.LayoutParams params1 = (RelativeLayout.LayoutParams) viewHolder.gallery.getLayoutParams();
        params1.height = (int) (350 * scale);
        viewHolder.gallery.setLayoutParams(params1);
    } else
    {
        RelativeLayout.LayoutParams params1 = (RelativeLayout.LayoutParams) viewHolder.gallery.getLayoutParams();
        params1.height = (int) (280 * scale);
        viewHolder.gallery.setLayoutParams(params1);
    }
}

class ViewHolder {
    TextView categoryTitle;
    Gallery gallery;

}

}

GalleryAdapter.java:

public class GalleryAdapter extends BaseAdapter {

final String TAG_PORTRAIT = "portrait";
LayoutInflater inflater;
ImageLoader imageLoader;
DisplayImageOptions options;
Context context;
List<BaseAssets> baseAssetsList;

Gallery.LayoutParams params;

public GalleryAdapter(Context context, List<BaseAssets> baseAssetsList) {
    imageLoader = ImageLoader.getInstance();
    options = new DisplayImageOptions.Builder().cacheOnDisc().imageScaleType(ImageScaleType.EXACTLY).bitmapConfig(Bitmap.Config.RGB_565).cacheInMemory().showStubImage(
            R.drawable.no_preview).build();
    this.context = context;
    this.baseAssetsList = baseAssetsList;
    inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);

}

public int getCount() {
    return baseAssetsList.size();
}

public Object getItem(int position) {
    return position;
}

public long getItemId(int position) {
    return position;
}

public View getView(final int position, View convertView, ViewGroup parent) {

    ViewHolder viewHolder;
    if (convertView == null)
    {
        viewHolder = new ViewHolder();
        convertView = inflater.inflate(R.layout.gallery_list_item, parent, false);
        viewHolder.galleryWrapper = (RelativeLayout) convertView.findViewById(R.id.gallery_wrapper);
        viewHolder.downloadThumbnail = (ImageView) convertView.findViewById(R.id.thumbnailDownloadStatus);
        viewHolder.assetImage = (ImageView) convertView.findViewById(R.id.thumbnail_image);
        viewHolder.assetName = (TextView) convertView.findViewById(R.id.thumbnail_name);
        convertView.setTag(viewHolder);
    } else
        viewHolder = (ViewHolder) convertView.getTag();

    final float scale = context.getResources().getDisplayMetrics().density;

    if (baseAssetsList.get(position).thumbOrientation.equals(TAG_PORTRAIT))
    {

        params = new Gallery.LayoutParams((int) (166 * scale), (int) (245 * scale));
        viewHolder.galleryWrapper.setLayoutParams(params);

    } else
    {
        params = new Gallery.LayoutParams((int) (238 * scale), (int) (191 * scale));
        viewHolder.galleryWrapper.setLayoutParams(params);
    }

    viewHolder.assetName.setText(baseAssetsList.get(position).contentTitle);
    String raw_url = baseAssetsList.get(position).thumbnail;
    String correctUrl = correctUrl(raw_url);
    imageLoader.displayImage(correctUrl, viewHolder.assetImage, options);

    convertView.setOnClickListener(new View.OnClickListener() {

        public void onClick(View v) {
            Intent intent = new Intent(context, DownloadActivity.class);
            intent.putExtra(Universal.ASSET_TYPE, baseAssetsList.get(position).contentType);
            intent.putExtra(Universal.ASSET_TITLE, baseAssetsList.get(position).contentTitle);
            intent.putExtra(Universal.ASSET_URL, baseAssetsList.get(position).path);
            intent.putExtra(Universal.ASSET_LARGE_THUMBNAIL, baseAssetsList.get(position).thumbnail);

            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

            context.startActivity(intent);

        }
    });

    return convertView;
}

public String correctUrl(String raw_url) {
    String corrected_url = raw_url;
    if (!raw_url.contains("http:/"))
        corrected_url = ("http:/" + raw_url);
    return corrected_url;
}

class ViewHolder {
    RelativeLayout galleryWrapper;
    ImageView assetImage;
    ImageView downloadThumbnail;
    TextView assetName;

}

}

Was it helpful?

Solution 2

Try changing the "viewHolder = new ViewHolder();" inside the getview of Adapter if the convertview is null;

Like :

public View getView(final int position, View convertView, ViewGroup parent) {
String catID = categoryList.get(position).catID;

if (convertView == null)
{
    viewHolder = new ViewHolder(); //Add this line. Otherwise u are sharing the same instance for other views.
    convertView = inflater.inflate(R.layout.category_list_item, parent, false);
    viewHolder.categoryTitle = (TextView) convertView.findViewById(R.id.category_title);
    viewHolder.gallery = (Gallery) convertView.findViewById(R.id.gallery);
    convertView.setTag(viewHolder);
} else
    viewHolder = (ViewHolder) convertView.getTag();

assetTable = new AssetsTable(context);
int count = assetTable.getCountOfParticularCategory(catID);

initializeGallery(catID);

String text = categoryList.get(position).catName + "  (" + count + ")  ";
viewHolder.categoryTitle.setText(text);
return convertView;

}

OTHER TIPS

In your ListViewAdapter you are not calling

viewHolder = new ViewHolder();

in getView() when convertView is null.

Check it! That might be the problem.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top