1

我正在使用带有部分和部分标题的 ListView。下面是没有 ViewHolder 类的适配器的 GetView 方法,它工作正常,但是当滚动几次时,会冻结 UI 并在多个设备上杀死应用程序。

@Override
public View getView(int position, View v, ViewGroup parent) 
{
    //View v = convertView;// = convertView;

    //System.out.println("getView " + position + " " + convertView);
    final Item i = items.get(position);
    if (i != null) 
        {
            if(i.isSection())
                {
                    SectionItem si = (SectionItem)i;

                    v = vi.inflate(R.layout.list_item_section, null);

                    v.setOnClickListener(null);
                    v.setOnLongClickListener(null);
                    v.setLongClickable(false);

                    final TextView sectionView = (TextView) v.findViewById(R.id.list_item_section_text);
                    sectionView.setTypeface(StaticUtils.sTypeFace(context));
                    sectionView.setText(si.getTitle());
                    v.setEnabled(false);
                }
            else
                {
                    EntryItem ei = (EntryItem)i;
                    v = vi.inflate(R.layout.list_item_entry, null);

                    final TextView title = (TextView)v.findViewById(R.id.list_item_entry_title);
                    final ImageView mImg = (ImageView)v.findViewById(R.id.list_item_entry_drawable);
                    mImg.getLayoutParams().height = mIvPrams;
                    mImg.getLayoutParams().width = mIvPrams;
                    title.setTypeface(StaticUtils.sTypeFace(context));
                    title.setSelected(true);
                    if (title != null) 
                        title.setText(ei.title);
                    imageLoader.displayImage(ei.imgUrl, mImg, options, animateFirstListener);
                }       
        }
    return v;
}

现在,我尝试对其实现 ViewHolder 类以改善冻结问题。下面是我为适配器实现的 ViewHolder 类的代码。但是,当我使用以下实现滚动时,ListView 会变得混乱。它无法保存其元素的索引。如果我尝试进行更改,有时当我从下往上滚动时也会收到 NullPointerException。

@Override
public View getView(final int position, View v, ViewGroup parent) 
{
    //View v = null;// = convertView;

    //System.out.println("getView " + position + " " + convertView);
    final Item i = items.get(position);
    if (i != null) 
        {
            if(i.isSection())
                {
                    /*if (convertView == null) {
                        v = (View) vi.inflate(R.layout.list_item_section, null);
                        // Do some initialization
                    } else {
                        v = convertView;
                    }*/

                    if(v==null)
                        {
                            mHolder = new ViewHolder();
                            v = vi.inflate(R.layout.list_item_section, null);
                            mHolder.s = (SectionItem)i;
                            mHolder.mSectionView = (TextView) v.findViewById(R.id.list_item_section_text);
                            v.setTag(mHolder);
                        }
                    else
                        {
                            mHolder=(ViewHolder)v.getTag();
                            //v = convertView;
                        }

                    v.setOnClickListener(null);
                    v.setOnLongClickListener(null);
                    v.setLongClickable(false);

                    //final TextView sectionView = (TextView) v.findViewById(R.id.list_item_section_text);
                    mHolder.mSectionView.setTypeface(StaticUtils.sTypeFace(context));
                    mHolder.mSectionView.setText(mHolder.s.getTitle());
                    v.setEnabled(false);
                }
            else
                {

                    //v = vi.inflate(R.layout.list_item_entry, null);
                    if (v == null) {

                            mHolder = new ViewHolder();
                        v = (View) vi.inflate(R.layout.list_item_entry, null);
                        mHolder.e = (EntryItem)i;
                        mHolder.mTitle = (TextView)v.findViewById(R.id.list_item_entry_title);
                        mHolder.mImg = (ImageView)v.findViewById(R.id.list_item_entry_drawable);
                        mHolder.mImg.getLayoutParams().height = mIvPrams;
                        mHolder.mImg.getLayoutParams().width = mIvPrams;
                        v.setTag(mHolder);
                        // Do some initialization
                    } else {
                        mHolder=(ViewHolder)v.getTag();
                    }

                    //mHolder.mTitle.setTypeface(StaticUtils.sTypeFace(context));
                    //mHolder.mTitle.setSelected(true);
                    if (mHolder.mTitle != null) 
                        mHolder.mTitle.setText(mHolder.e.title);
                    imageLoader.displayImage(mHolder.e.imgUrl, mHolder.mImg, options, animateFirstListener);
                }       
        }
    return v;
}


public class ViewHolder
{
    TextView mSectionView, mTitle;
    ImageView mImg;
    EntryItem e;
    SectionItem s;
}

我希望得到一个解决方案,说明如何改进我的代码并为此适配器编写适当的 ViewHolder 类。

4

1 回答 1

1

你得到了,NullPointerExceptions因为你膨胀了两种类型的视图,当你滚动时,Android会重用你的视图,但在某些时候它会让你评估R.layout.list_item_entryisSection()真,反之亦然:评估R.layout.list_item_sectionisSection()假。

您需要做的是在您的适配器中实现另外两种方法:
-getViewTypeCount()这需要返回您正在膨胀的视图类型的数量。在您的情况下,您需要返回 2。 -getItemViewType(int position)基于位置,您需要返回 0 或 1。

现在,在您的适配器中,首先通过调用检测项目视图类型getItemViewType,然后应用您当前的逻辑。

编辑使用基于上述getView方法的盲编码,该方法如下所示(我没有检查它的可编译性,但我相信你会理解我的意思):

@Override
public int getViewTypeCount() {
    return 2;
}

@Override
public int getItemViewType(int position) {
    Item i = items.get(position);
    if(i.isSection()) {
        return 0;
    }
    return 1;
}

@Override
public View getView(final int position, View v, ViewGroup parent) {
    final Item i = items.get(position);
    int itemViewType = getItemViewType(position);
    ViewHolder viewHolder = null;
    if (itemViewType == 0) {
        if (v == null) {
            viewHolder = new ViewHolder();
            v = vi.inflate(R.layout.list_item_section, null);
            viewHolder.mSectionView = (TextView) v.findViewById(R.id.list_item_section_text);
            v.setTag(mHolder);
        } else {
            viewHolder = (ViewHolder) v.getTag();
        }

        v.setOnClickListener(null);
        v.setOnLongClickListener(null);
        v.setLongClickable(false);

        //final TextView sectionView = (TextView) v.findViewById(R.id.list_item_section_text);
        viewHolder.mSectionView.setTypeface(StaticUtils.sTypeFace(context));
        viewHolder.mSectionView.setText(mHolder.s.getTitle());
        v.setEnabled(false);
    } else {
        EntryItem e = (EntryItem) i;
        //v = vi.inflate(R.layout.list_item_entry, null);
        if (v == null) {
            viewHolder = new ViewHolder();
            v = (View) vi.inflate(R.layout.list_item_entry, null);
            viewHolder.mTitle = (TextView) v.findViewById(R.id.list_item_entry_title);
            viewHolder.mImg = (ImageView) v.findViewById(R.id.list_item_entry_drawable);
            viewHolder.mImg.getLayoutParams().height = mIvPrams;
            viewHolder.mImg.getLayoutParams().width = mIvPrams;
            v.setTag(mHolder);
            // Do some initialization
        } else {
            viewHolder = (ViewHolder) v.getTag();
        }

        //mHolder.mTitle.setTypeface(StaticUtils.sTypeFace(context));
        //mHolder.mTitle.setSelected(true);
        if (viewHolder.mTitle != null)
            viewHolder.mTitle.setText(mHolder.e.title);
        imageLoader.displayImage(e.imgUrl, viewHolder.mImg, options, animateFirstListener);
    }
    return v;
}

观察:不要将数据模型类保留在 Holder 类中,因为持有者将在不同位置的其他类似视图中重用,并且您保留在 Holder 中的数据模型类对该位置无效。您已经有了getItem(position)可用的方法。改用那个!

于 2014-01-20T05:40:02.743 回答