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 ?
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 ...