0

So I've been creating a custom view similar to GridView. It loads and scrolls through images just fine when they are resources inside the app but now that I'm using images coming in through an HTTP request, the images aren't loading correctly.

When the app starts: all images are set to the default (bad)

After scrolling past that cell and immediately scrolling back to it: image loads correctly (good)

After scrolling back to that same cell sometime later: image was set back to the default (bad)

Does anyone have any ideas of what could be causing this error? I assume it's some kind of recycling issue but I haven't been able to fix it.

Here is my xml file:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:paddingBottom="1dip" 
    android:background="@color/white"
    android:id="@+id/highlight_counter_container"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_alignParentLeft="true"
    android:gravity="center" >

    <ImageView
        android:id="@+id/catalog_image"
        android:layout_width="match_parent"

        android:layout_height="match_parent"/>

    <View
        android:id="@+id/solid"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:background="@android:color/black" />

    <View
        android:id="@+id/text_gradient"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_above="@id/solid"
        android:background="@drawable/highlight_text_gradient" />

        <TextView
            android:id="@+id/title"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:layout_alignParentBottom="true"
            android:padding="@dimen/highlight_text_padding"
            android:ellipsize="end"
            android:gravity="bottom"
            android:maxLines="2"
            android:textColor="@color/white"
            android:textSize="@dimen/text_large" />
</RelativeLayout>

Here is an excerpt from my adapter (where I think the problem probably lies):

 @Override
public View getView(int position, View convertView, ViewGroup parent) {
    final LayoutParams lp;
    int viewType = getItemViewType(position);
    ImageView img;
    PulseTextView title;
    Resources res = getContext().getResources();
    int height = (int) res.getDimension(R.dimen.icon_main_size);
    if (convertView == null) {
        LayoutInflater inflater = (LayoutInflater) mContext.get().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        convertView = inflater.inflate(R.layout.element_item, parent, false)

        LayoutParams layp = new LayoutParams(height);
        convertView.setLayoutParams(layp);
    } 
    img = ViewHolder.get(convertView,R.id.catalog_image);
    title = ViewHolder.get(convertView,R.id.title);


    final CatalogItem channel = getCatalogItem(position);

    // find the url of the associated image then set image
    String url = null;
    try {
        url = mCatalogHandler.getImageUrl(CatalogHandler.VALUE_ICON, channel.mPrimaryKey, 100, 100);
    } catch (CatalogException e) {
        e.printStackTrace();
    }
    if (url == null || TextUtils.isEmpty(url) || url.equals("null")) {
        img.setImageBitmap(mDefaultPic);
    } else {
        // downloads the image to img
        mImageDownloader.download(url, img, mDefaultPic, false);
    }
    title.setText(channel.mDomain);
    img.setScaleType(ScaleType.FIT_XY);
    img.setTag(RAMImageCache.KEY_URL, url);

    // set the gradient behind the text
    View grad = convertView.findViewById(R.id.text_gradient);
    ViewUtils.setHeight(grad, height * 3 / 5);
    grad.getBackground().setDither(true);
    View solid = convertView.findViewById(R.id.solid);
    ViewUtils.setHeight(solid, height / 5);

    // set the padding based on the position on the screen
    DisplayMetrics displaymetrics = new DisplayMetrics();
    ((Activity)getContext()).getWindowManager().getDefaultDisplay().getMetrics(displaymetrics);
    int width = displaymetrics.widthPixels;
    if (convertView.getRight() == width && convertView.getLeft() == 0) {
        convertView.setPadding(0, 0, 0, 1);
    } else if (convertView.getRight() == width) {
        //convertView.setPadding(1, 0, 0, 1);
        convertView.setPadding(0, 0, 1, 1);
    } else if (convertView.getLeft() == 0) {
        //convertView.setPadding(0, 0, 1, 1);
        convertView.setPadding(1, 0, 0, 1);
    }

    // set the onclicklistener to jump to the next fragment
    convertView.setOnClickListener(new OnClickListener() {
        @Override
        public void onClick(View view) {
            Bundle bundle = new Bundle();
            bundle.putString("channelitem", channel.getMetadata().toString());
            ChannelFragment fragment = new ChannelFragment();
            fragment.setArguments(bundle);
            ((PulseFragmentActivity)mContext.get()).openFragment(fragment);
        }
});
    return convertView;
}

static class ViewHolder {
    ImageView img;
    TextView title;

    public ViewHolder(ImageView i, PulseTextView t) {
        img = i;
        title = t;
    }

    public static <T extends View> T get(View view, int id) {
        SparseArray<View> viewHolder = (SparseArray<View>) view.getTag();
        if (viewHolder == null) {
            viewHolder = new SparseArray<View>();
            view.setTag(viewHolder);
        }
        View childView = viewHolder.get(id);
        if (childView == null) {
            childView = view.findViewById(id);
            viewHolder.put(id, childView);
        }
        return (T) childView;
    }
}

Any point in the right direction would help greatly! Let me know if there are any other code snippets you would need to see.

rakoonise
  • 529
  • 3
  • 16
  • check this link displaying images in listview using Universal Image Loader. instead of listview use gridview http://stackoverflow.com/questions/16789676/caching-images-and-displaying/16978285#16978285 – Raghunandan Jun 10 '13 at 05:17

2 Answers2

0

I suggest one way to debug is to try another image download library to find out if the error is in your code. I used https://github.com/koush/UrlImageViewHelper and it works well when cell is reused, and its API is similar to what you used now

thomasdao
  • 2,927
  • 1
  • 28
  • 24
0

The behaviour very much depends on what and how does your mImageDownloader handles the downloaded image.

In most cases LRU Cache implementation might be used to store your downloaded image and this cache has a maximum value of bytes assigned. Once your cached image exceeded this value, the old bitmaps will be discarded, hence why you are seeing default image and you need to re-download it.

My suggestion is after you have downloaded the image, scale it as small as you can, so that you can cache as much bitmaps as you could.

There is no way Android could cache up all your downloaded images due to memory restriction.

Chor Wai Chun
  • 3,226
  • 25
  • 41