12

I have one ListView and one BaseAdapter.I am downloading Products from webservice and display on listview.It displays properly on listview.

But when I scroll ListView displays rows in random position means sometimes third row display in first position, middle position row display on last position and so on.

This is my adapter class

public class ProductListAdapter extends BaseAdapter implements OnClickListener{

    LayoutInflater inflater;
    ArrayList<Product> arrProducts;
    Context c;

    public ProductListAdapter(Context c, ArrayList<Product> arrProducts) {
        super();
        inflater = LayoutInflater.from(c);
        this.arrProducts = arrProducts;
        this.c = c;
    }

    @Override
    public int getCount() {
        return arrProducts.size();
    }

    @Override
    public Object getItem(int position) {
        return arrProducts.get(position);
    }

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

    @Override
    public View getView(int position, View v, ViewGroup parent) {
        Product product = null;
        if(v == null) {
            v = inflater.inflate(R.layout.product_listview_row, null);
            product = (Product) getItem(position);
            v.setTag(product);
        }else {
            product = (Product)v.getTag();
        }

        v.setOnClickListener(this);

        TextView tvProductname = (TextView)v.findViewById(R.id.tvProductname);
        tvProductname.setText(product.getTitle());

        String strReviewCount = product.getReviews();
        TextView tvReviewsCounts = (TextView)v.findViewById(R.id.tvReviews);
        if(strReviewCount != null) tvReviewsCounts.setText(strReviewCount +" Reviews");

        Button btnPrice = (Button)v.findViewById(R.id.btnPrice);
        btnPrice.setText(product.getSellingPrice());

        return v;
    }

    @Override
    public void onClick(View v) {
        Product product = (Product) v.getTag();
        Intent i = new Intent(c, ProductDetails.class);
        i.putExtra(Product.PROD_ID, product.getId());
        startActivity(i);
    }

    @Override
    public int getItemViewType(int position) {
        return super.getItemViewType(position);
    }

    @Override
    public int getViewTypeCount() {
        return super.getViewTypeCount();
    }
}

This is ListView on XML layout

<ListView android:id="@+id/lstProducts" style="@style/fill_parent"
        android:dividerHeight="1dp" android:divider="#dbd3c5"
        android:scrollbars="vertical" android:layout_below="@id/layLine"></ListView>

Also when I change getView() method of BaseAdapter like this it is working fine

@Override
    public View getView(int position, View v, ViewGroup parent) {
        Product product = null;
        v = inflater.inflate(R.layout.product_listview_row, null);
        product = (Product) getItem(position);
        v.setTag(product);
        v.setOnClickListener(this);

        TextView tvProductname = (TextView)v.findViewById(R.id.tvProductname);
        tvProductname.setText(product.getTitle());

        String strReviewCount = product.getReviews();
        TextView tvReviewsCounts = (TextView)v.findViewById(R.id.tvReviews);
        if(strReviewCount != null) tvReviewsCounts.setText(strReviewCount +" Reviews");

        Button btnPrice = (Button)v.findViewById(R.id.btnPrice);
        btnPrice.setText(product.getSellingPrice());

        return v;
    }

But problem in this type is I am displaying image of product on listview row which I had not consider here.By using this type of code getView() method always create new View when ever scroll of listView so that I have to download image again and again.I used ImageLoader class which is using cash memory for download images but problem is that when I set image to ImageView many times it giving me out of memory error.

Please help me out from this problem.

Thanks

Dharmendra
  • 33,296
  • 22
  • 86
  • 129

2 Answers2

10

I landed here because of a link to the right solution.

The problem here is that you bind your product once to the view when you create a new view. You should call this on every call of getView:

product = (Product) getItem(position);
v.setTag(product);

But you could call v.setOnClickListener(this) once you create the view (it won't change anyway).

This should do the trick. The view type implementation is just misused here. I recommend to read my answer here...

Community
  • 1
  • 1
Knickedi
  • 8,742
  • 3
  • 43
  • 45
  • I know my answer was not the exact way to be used but for temporary purpose I managed it using view type. Hope your solution works and gets checked. – Lalit Poptani Oct 15 '11 at 07:26
  • Thank you. I hope you don't feel offended, that wasn't my intention. The problem here was that people accept the *trick* as normal and working and then get really confused when things go wrong later or they want to use a real view type implementation... I just wanted it to be clear, instead starting rumors ;-) – Knickedi Oct 15 '11 at 10:13
  • No no, its good for me too to get the exact solution. Personally I think that your answer will surely work and I will also try it out. And feeling bad is never a case, I am also here to learn. This is got something new from you. Thanks. – Lalit Poptani Oct 15 '11 at 10:17
  • Also, a very good article on Adapters: http://www.piwai.info/android-adapter-good-practices/ – eightyfive May 12 '13 at 09:17
5

Therefore, according to the recommendations made by Knickedi, the getView() method should look like:

public View getView(int position, View v, ViewGroup parent) {

    TextView tvProductname;
    TextView tvReviewsCounts;
    Button btnPrice;

    // Phase 1...
    if (v == null) {
        v = inflater.inflate(R.layout.product_listview_row, null);
        v.setOnClickListener(this);

        tvProductname = (TextView)v.findViewById(R.id.tvProductname);
        tvReviewsCounts = (TextView)v.findViewById(R.id.tvReviews);
        btnPrice = (Button)v.findViewById(R.id.btnPrice);

        v.setTag(R.id.tvProductname, tvProductname);
        v.setTag(R.id.tvReviews, tvReviewsCounts);
        v.setTag(R.id.btnPrice, btnPrice);
    }
    else {
        tvProductname = (TextView) v.getTag(R.id.tvProductname);
        tvReviewsCounts = (TextView) v.getTag(R.id.tvReviews);
        btnPrice = (Button) v.getTag(R.id.btnPrice);   
    }

    // Phase 2...
    Product product = (Product) getItem(position);

    tvProductname.setText(product.getTitle());
    btnPrice.setText(product.getSellingPrice());

    String strReviewCount = product.getReviews();
    if(strReviewCount != null)
        tvReviewsCounts.setText(strReviewCount +" Reviews");

    return v;
}
Community
  • 1
  • 1
eightyfive
  • 4,601
  • 3
  • 35
  • 44