0

I'm using custom data adapter for a ListView which is listing some categories in my app. When i add a new category or scroll ListView every item mixing, somehow it's not creating a new item for newly added data. Here is the code of my custom adapter ;

public class CategoryAdapter extends BaseAdapter {

List<Category> mList;
Context mContext;

public CategoryAdapter(Context context, List<Category> data) {
    mList = data;
    mContext = context;
}

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

@Override
public Object getItem(int position) {
    if (position < 0 || position >= mList.size())
        return null;
    return mList.get(position);
}

@Override
public long getItemId(int position) {
    if (position < 0 || position >= mList.size())
        return -1;
    return mList.get(position).getId();
}

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    CategoryDelegate del;
    if (convertView == null) {
        System.out.println("CV Null pos: " + position);
        del = new CategoryDelegate(mContext, mList.get(position));
        int height = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 67, parent.getResources().getDisplayMetrics());
        del.setLayoutParams(new ListView.LayoutParams(LayoutParams.MATCH_PARENT, height));
    } else {
        System.out.println("CV EXIST pos: " + position + " / " + mList.get(position).getTitle() + " =? " + ((CategoryDelegate) convertView).getCategory().getTitle());
        del = (CategoryDelegate) convertView;
    }
    return del;
}

public void setData(List<Category> data) {
    mList = data;
    notifyDataSetChanged();
}

public class CategoryDelegate extends LinearLayout {
    private TextView mTitle;
    private TextView mCount;
    private Category mCategory;

    public CategoryDelegate(Context context, Category category) {
        super(context);
        mCategory = category;

        Resources res = getResources();

        //leftMargin = 11dp; textAlignVCenter; fontSize = 20dp(sp!); color = Color.rgb(149, 155, 171); 
        mTitle = new TextView(context);
        mTitle.setTextColor(Color.rgb(149, 155, 171));
        mTitle.setGravity(Gravity.CENTER_VERTICAL);
        mTitle.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 20);
        mTitle.setText(category.getTitle());
        LayoutParams titleParams = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT);
        titleParams.leftMargin = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 11, res.getDisplayMetrics());
        titleParams.weight = 1;
        mTitle.setLayoutParams(titleParams);
        addView(mTitle);

        //rightMargin = 10dp; textAlignVCenter; fontSize = 15dp(sp!); color = Color.rgb(149, 155, 171);
        mCount = new TextView(context);
        mCount.setTextColor(Color.rgb(149, 155, 171));
        mCount.setGravity(Gravity.CENTER_VERTICAL);
        mCount.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 20);
        mCount.setText(String.valueOf(category.getSize()));
        LayoutParams countParams = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT);
        countParams.gravity = Gravity.RIGHT;
        countParams.rightMargin = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 13, res.getDisplayMetrics());
        mCount.setLayoutParams(countParams);
        addView(mCount);
    }

    public Category getCategory() {
        return mCategory;
    }
}

When i add a new category or scroll down to list, in getView if (convertView == null) { never works, i don't know why, instead it goes to existing convertView and all data mixing up after that point. Any idea how can make work this Adapter ?

Nande kore
  • 784
  • 1
  • 8
  • 16

2 Answers2

0

If i change getView function as like ;

    @Override
public View getView(int position, View convertView, ViewGroup parent) {
    CategoryDelegate del;
    if (convertView == null) {
        del = new CategoryDelegate(mContext, mList.get(position));
        int height = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 67, parent.getResources().getDisplayMetrics());
        del.setLayoutParams(new ListView.LayoutParams(LayoutParams.MATCH_PARENT, height));
    } else {
        if (((CategoryDelegate) convertView).getId() != mList.get(position).getId()) {
            del = new CategoryDelegate(mContext, mList.get(position));
            int height = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 67, parent.getResources().getDisplayMetrics());
            del.setLayoutParams(new ListView.LayoutParams(LayoutParams.MATCH_PARENT, height));
        } else {
            del = (CategoryDelegate) convertView;
        }
    }
    return del;
}

ListView works fine, but i'm not sure if i'm doing something good or bad. Is there anyone can explain me what is going on there. Is there any chance to i'm cause to memory leak ?

EDIT : As I worried memory leak, above code exactly cause a memory leak, so i found a good article about view holder pattern worth read: http://lucasr.org/2012/04/05/performance-tips-for-androids-listview/

Then i changed my code ;

    @Override
public View getView(int position, View convertView, ViewGroup parent) {
    CategoryDelegate del;
    if (convertView == null) {
        del = new CategoryDelegate(mContext, mList.get(position));
        int height = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 67, parent.getResources().getDisplayMetrics());
        del.setLayoutParams(new ListView.LayoutParams(LayoutParams.MATCH_PARENT, height));
    } else {
        if (((CategoryDelegate) convertView).getId() != mList.get(position).getId()) {
            ((CategoryDelegate) convertView).updateDelegate(mList.get(position));
        }
        del = (CategoryDelegate) convertView;
    }
    return del;
}

Finally CategoryDelegate as like ;

        public void updateDelegate(Category category) {
        mTitle.setText(category.getTitle());
        mCount.setText(String.valueOf(category.getSize()));
        mCategory = category;
    }

Everything works like a charm right now ...

Community
  • 1
  • 1
Nande kore
  • 784
  • 1
  • 8
  • 16
0

When convertView != null, you need to update del with a new mList.get(position) value and update any View's using that value. An adapter will recycle view's to avoid re-instantiating a whole new view. So when you received a non-null convertView, you are receiving a recycled view. That means you'll need to update that view with any new data for the position. Note, a recycled view doesn't mean it's using the same position. It could have been from a View that was used in a completely different position.

Also, I should note that the way you are creating the view is not really a clean or recommended way. The better approach is to create a separate standalone class CategoryDelegate and then use that class directly in an XML file. Define all your attributes there and inflate that view.

Some further reading for ya: How GetView Works

Community
  • 1
  • 1
Ifrit
  • 6,791
  • 8
  • 50
  • 79