Java 在自定义游标适配器中正确实现ViewHolder模式?
这是我的自定义游标适配器:Java 在自定义游标适配器中正确实现ViewHolder模式?,java,android,adapter,Java,Android,Adapter,这是我的自定义游标适配器: public class TasksAdapter extends CursorAdapter implements Filterable { private final Context context; public TasksAdapter(Context context, Cursor c) { super(context, c); this.context = context; } /**
public class TasksAdapter extends CursorAdapter implements Filterable {
private final Context context;
public TasksAdapter(Context context, Cursor c) {
super(context, c);
this.context = context;
}
/**
* @see android.widget.CursorAdapter#newView(android.content.Context, android.database.Cursor, android.view.ViewGroup)
*/
@Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
LayoutInflater inflater = LayoutInflater.from(context);
View v = inflater.inflate(android.R.layout.simple_list_item_checked, parent, false);
ViewHolder holder = new ViewHolder();
holder.textview = (CheckedTextView)v.findViewById(android.R.id.text1);
v.setTag(holder);
return v;
}
/**
* @see android.widget.CursorAdapter#bindView(android.view.View, android.content.Context, android.database.Cursor)
*/
@Override
public void bindView(View view, Context context, Cursor cursor) {
ViewHolder holder = (ViewHolder)view.getTag();
int titleCol = cursor.getColumnIndexOrThrow(Tasks.TITLE);
int completedCol = cursor.getColumnIndexOrThrow(Tasks.COMPLETED);
String title = cursor.getString(titleCol);
boolean completed = Util.intToBool(cursor.getInt(completedCol));
holder.textview.setText(title);
holder.textview.setChecked(completed);
}
/**
* @see android.widget.CursorAdapter#runQueryOnBackgroundThread(java.lang.CharSequence)
*/
@Override
public Cursor runQueryOnBackgroundThread(CharSequence constraint) {
StringBuffer buffer = null;
String[] args = null;
if (constraint != null) {
buffer = new StringBuffer();
buffer.append("UPPER (");
buffer.append(Tasks.TITLE);
buffer.append(") GLOB ?");
args = new String[] { "*" + constraint.toString().toUpperCase() + "*" };
}
Cursor c = context.getContentResolver().query(Tasks.CONTENT_URI,
null, (buffer == null ? null : buffer.toString()), args,
Tasks.DEFAULT_SORT_ORDER);
c.moveToFirst();
return c;
}
/**
* @see android.widget.CursorAdapter#convertToString(android.database.Cursor)
*/
@Override
public CharSequence convertToString(Cursor cursor) {
final int titleCol = cursor.getColumnIndexOrThrow(Tasks.TITLE);
String title = cursor.getString(titleCol);
return title;
}
static class ViewHolder {
CheckedTextView textview;
}
}
这是否属于ViewHolder图案的约束?我不确定,因为这是一个游标适配器,没有
getView
。如果有任何问题或建议,请您指出。CursorAdapter
不会在每次需要新行时调用newView
;如果它已经有一个视图
,它将调用bindwiew
,因此所创建的视图实际上被重用
也就是说,正如Joseph在评论中指出的,您仍然可以使用ViewHolder,以避免重复调用findViewById
如果您仍然关心效率,请查看使用WeakHashMap
(一个WeakReferences
)的实现:
WeakHashMap mHolders=newweakhashmap();
我的类实现使用newView
和bindView
扩展了SimpleCorsAdapter,但没有ViewHolder
模式
private class CountriesAdapter extends SimpleCursorAdapter {
private LayoutInflater mInflater;
public CountriesAdapter(Context context, int layout, Cursor cursor, String[] from,
int[] to, LayoutInflater inflater) {
super(getActivity(), layout, cursor, from, to, CURSOR_ADAPTER_FLAGS);
mInflater = inflater;
}
@Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
return mInflater.inflate(R.layout.countries_list_row, parent, false);
}
@Override
public void bindView(View rowView, Context context, Cursor cursor) {
TextView tvCountry = (TextView) rowView.findViewById(R.id.countriesList_tv_countryName);
TextView tvOrgs = (TextView) rowView.findViewById(R.id.countriesList_tv_orgNames);
ImageView ivContinent =
(ImageView) rowView.findViewById(R.id.countriesList_iv_continentName);
// TODO: set texts of TextViews and an icon here
}
}
}
如果要重写
newView()
和bindView()
,则不需要在getView()
中执行任何额外操作CursorAdapter
有一个getView()
的实现,它委托给newView()
和bindView()
来强制执行行循环
findViewById()
在滚动ListView
时可能会频繁调用,这会降低性能。即使适配器
返回一个膨胀视图进行循环,您仍然需要查找元素并更新它们。为了避免这种情况,ViewHolder
模式很有用
下面是为天气应用程序实现的ViewHolder
模式示例:
public class ForecastAdapter extends CursorAdapter {
public ForecastAdapter(Context context, Cursor cursor, int flags) {
super(context, cursor, flags);
}
@Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
View view = LayoutInflater.from(context).inflate(
R.layout.list_item_forecast, parent, false);
ViewHolder viewHolder = new ViewHolder(view);
view.setTag(viewHolder);
return view;
}
@Override
public void bindView(View view, Context context, Cursor cursor) {
ViewHolder viewHolder = (ViewHolder) view.getTag();
long date = cursor.getLong(ForecastFragment.COL_WEATHER_DATE);
viewHolder.dateView.setText("Today");
String weatherForecast =
cursor.getString(ForecastFragment.COL_WEATHER_DESC);
viewHolder.descriptionView.setText(weatherForecast);
double high = cursor.getFloat(ForecastFragment.COL_WEATHER_MAX_TEMP);
viewHolder.highTempView.setText("30");
double low = cursor.getFloat(ForecastFragment.COL_WEATHER_MIN_TEMP);
viewHolder.lowTempView.setText("24");
int weatherConditionId =
cursor.getInt(ForecastFragment.COL_WEATHER_CONDITION_ID);
viewHolder.iconView.setImageResource(R.drawable.ic_snow);
}
/** Cache of the children views for a list item. */
public static class ViewHolder {
public final ImageView iconView;
public final TextView dateView;
public final TextView descriptionView;
public final TextView highTempView;
public final TextView lowTempView;
public ViewHolder(View view) {
iconView =
(ImageView) view.findViewById(R.id.item_icon);
dateView =
(TextView) view.findViewById(R.id.item_date_textview);
descriptionView =
(TextView) view.findViewById(R.id.item_forecast_textview);
highTempView =
(TextView) view.findViewById(R.id.item_high_textview);
lowTempView =
(TextView) view.findViewById(R.id.item_low_textview);
}
}
}
所以我可以进行昂贵的调用,比如View.findviewbyd(int),这样我的应用程序就不会延迟了?
findviewbyd(int)
没有你想象的那么昂贵。它将只返回一个引用(如果存在)。ViewHolder技术可以解决其他类型的问题:不要创建超出实际需要的视图(因此,它可以避免过度的视图膨胀,这是非常昂贵的)。@Cristian,谢谢。我使用newView
和bindwiew
使类扩展SimpleCursorAdapter
。请看下面的代码。@Cristian你又错了!从Commonware手册中,您可以找到不带ViewHolder的getView()实现,但它使用convertView。如您所见,当convertView不为null时,不需要充气:视图是循环的。因此,为了避免膨胀,必须使用convertView。取而代之的是,ViewHolder实际上用于避免许多findViewById调用,正如我现在看到的同一本公共软件书中所说的那样。convertView实例提供了避免膨胀的功能,而ViewHolder仅用于避免findViewById
调用。谢谢你让我明白这一点!
public class ForecastAdapter extends CursorAdapter {
public ForecastAdapter(Context context, Cursor cursor, int flags) {
super(context, cursor, flags);
}
@Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
View view = LayoutInflater.from(context).inflate(
R.layout.list_item_forecast, parent, false);
ViewHolder viewHolder = new ViewHolder(view);
view.setTag(viewHolder);
return view;
}
@Override
public void bindView(View view, Context context, Cursor cursor) {
ViewHolder viewHolder = (ViewHolder) view.getTag();
long date = cursor.getLong(ForecastFragment.COL_WEATHER_DATE);
viewHolder.dateView.setText("Today");
String weatherForecast =
cursor.getString(ForecastFragment.COL_WEATHER_DESC);
viewHolder.descriptionView.setText(weatherForecast);
double high = cursor.getFloat(ForecastFragment.COL_WEATHER_MAX_TEMP);
viewHolder.highTempView.setText("30");
double low = cursor.getFloat(ForecastFragment.COL_WEATHER_MIN_TEMP);
viewHolder.lowTempView.setText("24");
int weatherConditionId =
cursor.getInt(ForecastFragment.COL_WEATHER_CONDITION_ID);
viewHolder.iconView.setImageResource(R.drawable.ic_snow);
}
/** Cache of the children views for a list item. */
public static class ViewHolder {
public final ImageView iconView;
public final TextView dateView;
public final TextView descriptionView;
public final TextView highTempView;
public final TextView lowTempView;
public ViewHolder(View view) {
iconView =
(ImageView) view.findViewById(R.id.item_icon);
dateView =
(TextView) view.findViewById(R.id.item_date_textview);
descriptionView =
(TextView) view.findViewById(R.id.item_forecast_textview);
highTempView =
(TextView) view.findViewById(R.id.item_high_textview);
lowTempView =
(TextView) view.findViewById(R.id.item_low_textview);
}
}
}