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

2 種類のビューを膨張させているNullPointerExceptionsため、スクロールすると Android はビューを再利用しますが、ある時点でtrueR.layout.list_item_entryisSection()評価されるか、その逆R.layout.list_item_sectionisSection()評価が false に評価されるためです。

あなたがする必要があるのは、アダプタに他の 2 つのメソッドを実装することです:
-getViewTypeCount()これは、インフレートしているビュー タイプの数を返す必要があります。あなたの場合、2を返す必要があります。 - getItemViewType(int position)- 位置に基づいて、0または1のいずれかを返す必要があります。

ここで、アダプタで最初に呼び出してアイテム ビュー タイプを検出しgetItemViewType、次に現在のロジックを適用します。

EDIT上記に基づくブラインドコーディングでは、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 に答える