web-dev-qa-db-ja.com

ArrayAdapterをViewHolderパターンに準拠させるにはどうすればよいですか?

これが私のArrayAdapterです。 ViewHolderパターンに従うことで、これをより効率的にしたいと思います。

http://developer.Android.com/resources/samples/ApiDemos/src/com/example/Android/apis/view/List14.html

しかし、これを達成する方法がわかりません。

UPDATE:ViewHolderパターン

private class QuoteAdapter extends ArrayAdapter<Quote> {

    private ArrayList<Quote> items;
    // used to keep selected position in ListView
    private int selectedPos = -1; // init value for not-selected

    public QuoteAdapter(Context context, int textViewResourceId, ArrayList<Quote> items) {
        super(context, textViewResourceId, items);
        this.items = items;
    }

    public void setSelectedPosition(int pos) {
        selectedPos = pos;
        // inform the view of this change
        notifyDataSetChanged();
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        View v = convertView;
        ViewHolder holder; // to reference the child views for later actions

        if (v == null) {
            LayoutInflater vi = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            v = vi.inflate(R.layout.mainrow, null);

            // cache view fields into the holder
            holder = new ViewHolder();
            holder.nameText = (TextView) v.findViewById(R.id.nameText);
            holder.priceText = (TextView) v.findViewById(R.id.priceText);
            holder.changeText = (TextView) v.findViewById(R.id.changeText);

            // associate the holder with the view for later lookup
            v.setTag(holder);
        }
        else {
            // view already exists, get the holder instance from the view
            holder = (ViewHolder)v.getTag();
        }

        // change the row color based on selected state
        if (selectedPos == position) {
            v.setBackgroundResource(R.drawable.stocks_selected_gradient);
            holder.nameText.setTextColor(Color.WHITE);
            holder.priceText.setTextColor(Color.WHITE);
            holder.changeText.setTextColor(Color.WHITE);
        } else {
            v.setBackgroundResource(R.drawable.stocks_gradient);
            holder.nameText.setTextAppearance(getApplicationContext(), R.style.BlueText);
            holder.priceText.setTextAppearance(getApplicationContext(), R.style.BlueText);
            holder.changeText.setTextAppearance(getApplicationContext(), R.style.BlueText);
        }

        Quote q = items.get(position);
        if (q != null) {
            if (holder.nameText != null) {
                holder.nameText.setText(q.getSymbol());
            }
            if (holder.priceText != null) {
                holder.priceText.setText(q.getLastTradePriceOnly());
            }
            if (holder.changeText != null) {
                try {
                    float floatedChange = Float.valueOf(q.getChange());
                    if (floatedChange < 0) {
                        if (selectedPos != position)
                            holder.changeText.setTextAppearance(getApplicationContext(), R.style.RedText); // red
                    } else {
                        if (selectedPos != position)
                            holder.changeText.setTextAppearance(getApplicationContext(), R.style.GreenText); // green
                    }
                } catch (NumberFormatException e) {
                    System.out.println("not a number");
                } catch (NullPointerException e) {
                    System.out.println("null number");
                }
                holder.changeText.setText(q.getChange() + " (" + q.getPercentChange() + ")");
            }
        }
        return v;
    }
}
35
Sheehan Alam

ViewHolderは基本的に、作成時にビューに関連付ける静的クラスインスタンスであり、実行時に検索する子ビューをキャッシュします。ビューがすでに存在する場合は、findViewByIdを呼び出す代わりにホルダーインスタンスを取得し、そのフィールドを使用します。

あなたの場合:

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    View v = convertView;
    ViewHolder holder; // to reference the child views for later actions

    if (v == null) {
        LayoutInflater vi = 
            (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        v = vi.inflate(R.layout.mainrow, null);
        // cache view fields into the holder
        holder = new ViewHolder();
        holder.nameText = (TextView) v.findViewById(R.id.nameText);
        holder.priceText = (TextView) v.findViewById(R.id.priceText);
        holder.changeText = (TextView) v.findViewById(R.id.changeText);
        // associate the holder with the view for later lookup
        v.setTag(holder);
    }
    else {
        // view already exists, get the holder instance from the view
        holder = (ViewHolder) v.getTag();
    }
    // no local variables with findViewById here

    // use holder.nameText where you were 
    // using the local variable nameText before

    return v;
}

// somewhere else in your class definition
static class ViewHolder {
    TextView nameText;
    TextView priceText;
    TextView changeText;
}

警告:これをコンパイルしようとはしなかったので、一粒の塩を用意してください。

51
codelark

私はここで同様の問題に直面しましたが、少し複雑ですが、非常に類似したサンプルを検討してください。

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

    if (v == null) {
        LayoutInflater vi = 
            (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        v = vi.inflate(R.layout.mainrow, null);
        holder = new ViewHolder();
        holder.nameText = (TextView) v.findViewById(R.id.nameText);
        holder.priceText = (TextView) v.findViewById(R.id.priceText);
        holder.myCheckbox = (Checkbox) v.findViewById(R.id.changeText);
        v.setTag(holder);
    }
    else {
        holder = (ViewHolder) v.getTag();
        /*ATTENTION - this line below was added, because i started to face some problems with view reuse of other rows, when user changed the state, the behavior of other row was triggered*/
        holder.myCheckbox.setOnCheckedChangeListener(null);
    }
    /*without the new line above, the line below trigger the old event and some strange behavior happens.*/
    holder.myCheckbox.setChecked(myList.get(position).isChecked());
    holder.myCheckbox.setOnCheckedChangeListener(()->{
       //some behavior
    });



    return v;
}

// somewhere else in your class definition
static class ViewHolder {
    TextView nameText;
    TextView priceText;
    Checkbox myCheckbox;
}

したがって、ViewHolderパターンを使用するときは、コンポーネントリスナーの状態を変更する前に、コンポーネントリスナーをクリーンアップすることをお勧めします。

0