如何使 ArrayAdapter 遵循 ViewHolder 模式?

这是我的ArrayAdapter。我想通过遵循 ViewHolder 模式来提高效率:

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

但我不知道如何做到这一点。

更新:视图持有者模式

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

答案 1

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

警告:我没有试图编译这个,所以要带着一粒盐。


答案 2

我只是在这里遇到了一个类似的问题,但稍微复杂一点,考虑一个非常相似的样本。

@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 模式时,最好在更改组件侦听器的状态之前清理它们。


推荐