Java 如何让我的 ArrayAdapter 遵循 ViewHolder 模式?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/3832254/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How can I make my ArrayAdapter follow the ViewHolder pattern?
提问by Sheehan Alam
Here is my ArrayAdapter. I would like to make this more efficient by following the ViewHolder pattern:
这是我的 ArrayAdapter。我想通过遵循 ViewHolder 模式来提高效率:
but am not sure how to accomplish this.
但我不知道如何做到这一点。
UPDATE: ViewHolder Pattern
更新: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;
}
}
采纳答案by codelark
The ViewHolder is basically a static class instance that you associate with a view when it's created, caching the child views you're looking up at runtime. If the view already exists, retrieve the holder instance and use its fields instead of calling findViewById.
ViewHolder 基本上是一个静态类实例,您在创建时将其与视图关联,缓存您在运行时查找的子视图。如果视图已存在,则检索持有者实例并使用其字段而不是调用findViewById.
In your case:
在你的情况下:
@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;
}
caveat: I didn't try to compile this, so take with a grain of salt.
警告:我没有尝试编译这个,所以请谨慎对待。
回答by Rafael Rossignol
I just faced a similar problem here, but a little bit more complex, consider a very similar sample.
我刚刚在这里遇到了类似的问题,但稍微复杂一点,考虑一个非常相似的示例。
@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;
}
So, remember, when you use the ViewHolder Pattern, it's good to cleanup the component listeners before change the state of them.
因此,请记住,当您使用 ViewHolder 模式时,最好在更改它们的状态之前清理组件侦听器。

