Android DataAdapter混合数据值

时间:2014-08-27 12:31:51

标签: android listview android-listview baseadapter

我正在为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并且在该点之后混合所有数据。任何想法如何使这个适配器工作?

2 个答案:

答案 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;
}

最后像CategoryDe​​legate一样;

        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时,您将收到一个回收的视图。这意味着您需要使用该职位的任何新数据更新该视图。注意,循环视图并不意味着它使用相同的位置。它可能来自一个完全不同的位置使用的视图。

另外,我应该注意,创建视图的方式并不是一种干净或推荐的方式。更好的方法是创建一个单独的独立类CategoryDe​​legate,然后直接在XML文件中使用该类。在那里定义所有属性并使该视图膨胀。

进一步阅读ya:How GetView Works