我正在为ListView使用自定义数据适配器,它列出了我的应用中的一些类别。当我添加一个新类别或滚动ListView每个项目混合时,不知何故它不会为新添加的数据创建新项目。这是我的自定义适配器的代码;
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;
}
}
当我添加一个新类别或向下滚动到列表时,在getView if (convertView == null) {
中永远不会工作,我不知道为什么,而是转到现有的convertView并且在该点之后混合所有数据。任何想法如何使这个适配器工作?
答案 0 :(得分:0)
如果我改变了getView功能;
@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工作正常,但我不确定我做的是好还是坏。有谁能解释我那里发生了什么。有没有机会让我记忆泄漏?
编辑:由于我担心内存泄漏,上面的代码确实导致内存泄漏,所以我发现了一篇关于视图持有者模式值得阅读的好文章:{{3} }
然后我改变了我的代码;
@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;
}
最后像CategoryDelegate一样;
public void updateDelegate(Category category) {
mTitle.setText(category.getTitle());
mCount.setText(String.valueOf(category.getSize()));
mCategory = category;
}
现在一切都像魅力......
答案 1 :(得分:0)
当convertView != null
时,您需要使用新的mList.get(position)值更新del并使用该值更新任何View。适配器将回收视图以避免重新实例化整个新视图。因此,当您收到非null convertView时,您将收到一个回收的视图。这意味着您需要使用该职位的任何新数据更新该视图。注意,循环视图并不意味着它使用相同的位置。它可能来自一个完全不同的位置使用的视图。
另外,我应该注意,创建视图的方式并不是一种干净或推荐的方式。更好的方法是创建一个单独的独立类CategoryDelegate,然后直接在XML文件中使用该类。在那里定义所有属性并使该视图膨胀。
进一步阅读ya:How GetView Works