ViewHolder主要作用是Hold住View的Hierarchy以减少findViewById()的调用,在这里介绍ViewHolder的另一种实现思路。(PS:名字是我瞎编的)

轻量ViewHolder模式

这是最普遍的使用方式,一种优雅的变种是使用ViewHolder的构造方法来实现View的绑定。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
class ViewHolder {
ImageView icon;
TextView title;
TextView subtitle;
}

// Inside the adapter
public void getView(int position, View convertView, ViewGroup parent) {
// if convertView is null, the view is newly inflated.
// else, re-assign new values.
ViewHolder holder;
if (convertView == null) {
convertView = LayoutInflater.from(context).inflate(R.layout.row, null);

// Set up the ViewHolder.
holder = new ViewHolder();
holder.icon = (ImageView) findViewById(R.id.icon);
holder.title = (TextView) findViewById(R.id.title);
holder.subtitle = (TextView) findViewById(R.id.subtitle);

// Store the holder with the view.
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}

// Assign values
holder.icon.setImageDrawable(some_image);
holder.title.setText(some_text);
holder.subtitle.setText(some_text);
}

View内含模式

使用扩展ViewGroup的内部变量Hold住View的方式,参考自:infamous-viewholder-pattern

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
// Custom class for ListRow
public class ListRow extends RelativeLayout {
private ImageView mIcon;
private TextView mTitle;
private TextView mSubtitle;

public ListRow(Context context, AttributeSet attrs) {
// RelativeLayout intializations happen here.
LayoutInflater.from(context).inflate(R.layout.row, this);

// Store the views.
mIcon = (ImageView) findViewById(R.id.icon);
mTitle = (TextView) findViewById(R.id.title);
mSubtitle = (TextView) findViewById(R.id.subtitle);
}

public void setIcon(Drawable drawable) {
mIcon.setImageDrawable(drawable);
}

public void setTitle(String text) {
mTitle.setText(text);
}

public void setSubtitle(String subtitle) {
mSubtitle.setText(text);
}
}

// Inside the adapter
public void getView(int position, View convertView, ViewGroup parent) {
// if convertView is null, the view is newly inflated.
// else, re-assign new values.
ListRow row;
if (convertView == null) {
// Inflation happens automagically.
row = new ListRow(context, null);
convertView = row;
} else {
row = (ListRow) convertView;
}

// Assign values
row.setIcon(some_image);
row.setTitle(some_text);
row.setSubtitle(some_text);
}

RecyclerView托管模式

RecyclerView内部处理了ViewHolder的绑定,你只需要实现几个方法,类似于以上第一种方式。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
public static abstract class Adapter<VH extends ViewHolder> {
...
//需要实现的方法
public abstract VH onCreateViewHolder(ViewGroup parent, int viewType);
...
public abstract void onBindViewHolder(VH holder, int position);
...
public final VH createViewHolder(ViewGroup parent, int viewType) {
TraceCompat.beginSection(TRACE_CREATE_VIEW_TAG);
//在这里被调用
final VH holder = onCreateViewHolder(parent, viewType);
holder.mItemViewType = viewType;
TraceCompat.endSection();
return holder;
}
...
//绑定发生在这里
public final void bindViewHolder(VH holder, int position) {
holder.mPosition = position;
if (hasStableIds()) {
holder.mItemId = getItemId(position);
}
holder.setFlags(ViewHolder.FLAG_BOUND,
ViewHolder.FLAG_BOUND | ViewHolder.FLAG_UPDATE | ViewHolder.FLAG_INVALID
| ViewHolder.FLAG_ADAPTER_POSITION_UNKNOWN);
TraceCompat.beginSection(TRACE_BIND_VIEW_TAG);
onBindViewHolder(holder, position);
TraceCompat.endSection();
}
...
}