Android:自定义SimpleCursorAdapter中的newView和bindView问题

我从我发现的唯一一个例子中创建了一个自定义的SimpleCursorAdapter。

当我的ListActivity被调用时,我的每个数据库条目都会调用newView和bindView,并为每个条目再次调用。 我有几个问题:

– 这是正确的例子(如果没有,我在哪里可以find一个)?

-if bindView调用总是在newView调用之前,为什么在两个函数中都这样做?

为什么是newView-bindView序列为每个项目调用两次?

为什么有些CursorAdapter示例使用getView而不是newView和bindView?

基本上,应该如何使用SimpleCursorAdapter,以及我的代码有什么问题?

谢谢


ListActivity

public class ContactSelection extends ListActivity { private WhipemDBAdapter mDbHelper; private FriendAdapter friendAdapter; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mDbHelper = new WhipemDBAdapter(this); mDbHelper.open(); setContentView(R.layout.contact_list); Cursor c = mDbHelper.fetchAllFriends(); startManagingCursor(c); String[] from = new String[] {}; int[] to = new int[] {}; this.friendAdapter = new FriendAdapter(this, R.layout.contact_row, c, from, to); setListAdapter(this.friendAdapter); getListView().setItemsCanFocus(false); getListView().setChoiceMode(ListView.CHOICE_MODE_MULTIPLE); } @Override protected void onResume() { super.onResume(); mDbHelper.open(); } @Override protected void onPause() { super.onPause(); mDbHelper.close(); } } 

自定义SimpleCursorAdapter

 public class FriendAdapter extends SimpleCursorAdapter implements OnClickListener { private Context mContext; private int mLayout; public FriendAdapter(Context context, int layout, Cursor c, String[] from, int[] to) { super(context, layout, c, from, to); this.mContext = context; this.mLayout = layout; } @Override public View newView(Context context, Cursor cursor, ViewGroup parent) { Cursor c = getCursor(); final LayoutInflater inflater = LayoutInflater.from(context); View v = inflater.inflate(mLayout, parent, false); String name = c.getString(c.getColumnIndex(WhipemDBAdapter.KEY_NAME)); String fb_id = c.getString(c.getColumnIndex(WhipemDBAdapter.KEY_FB_ID)); TextView name_text = (TextView) v.findViewById(R.id.contact_name); if (name_text != null) { name_text.setText(name); } ImageView im = (ImageView) v.findViewById(R.id.contact_pic); Drawable drawable = LoadImageFromWebOperations("http://graph.facebook.com/"+fb_id+"/picture"); if (im != null) { im.setImageDrawable(drawable); } CheckBox bCheck = (CheckBox) v.findViewById(R.id.checkbox); if (im != null) { bCheck.setTag(fb_id); } if (((GlobalVars) mContext.getApplicationContext()).isFriendSelected(fb_id)) bCheck.setChecked(true); bCheck.setOnClickListener(this); return v; } @Override public void bindView(View v, Context context, Cursor c) { String name = c.getString(c.getColumnIndex(WhipemDBAdapter.KEY_NAME)); String fb_id = c.getString(c.getColumnIndex(WhipemDBAdapter.KEY_FB_ID)); TextView name_text = (TextView) v.findViewById(R.id.contact_name); if (name_text != null) { name_text.setText(name); } ImageView im = (ImageView) v.findViewById(R.id.contact_pic); Drawable drawable = LoadImageFromWebOperations("http://graph.facebook.com/"+fb_id+"/picture"); if (im != null) { im.setImageDrawable(drawable); } CheckBox bCheck = (CheckBox) v.findViewById(R.id.checkbox); if (im != null) { bCheck.setTag(fb_id); } ArrayList dude = ((GlobalVars) mContext.getApplicationContext()).getSelectedFriendList(); if (((GlobalVars) mContext.getApplicationContext()).isFriendSelected(fb_id)) bCheck.setChecked(true); bCheck.setOnClickListener(this); } @Override public void onClick(View v) { CheckBox cBox = (CheckBox) v; String fb_id = (String) cBox.getTag(); if (cBox.isChecked()) { if (!((GlobalVars) mContext.getApplicationContext()).isFriendSelected(fb_id)) ((GlobalVars) mContext.getApplicationContext()).addSelectedFriend(fb_id); } else { if (((GlobalVars) mContext.getApplicationContext()).isFriendSelected(fb_id)) ((GlobalVars) mContext.getApplicationContext()).removeSelectedFriend(fb_id); } } private Drawable LoadImageFromWebOperations(String url) { try { InputStream is = (InputStream) new URL(url).getContent(); Drawable d = Drawable.createFromStream(is, "src name"); return d; }catch (Exception e) { System.out.println("Exc="+e); return null; } } } 

覆盖getView()函数使您可以“重新使用”已经膨胀的列表项(当您滚动列表来回时,从当前视图端口“滚出”的列表项)。

通过这样做,您将节省大量内存资源和处理器运行时间,因为充气是一项非常耗时的操作。 对于您重复使用的每个convertView ,您还可以保存GC运行时(因为垃圾收集器不必收集该特定列表项)。

您还可以创建一个“视图集合”类(以下示例中的ViewHolder类),该类将保存充气列表项中每个视图的引用。 这样,您不必每次使用新值更新列表项时都find它们(通常不会滚动列表)。 findViewById()也是一个相当耗时的操作。

此外,我认为您可以缓存更多variables,如布局inflater和列索引。 一切都节省时间:-)

 private final Context mContext; private final int mLayout; private final Cursor mCursor; private final int mNameIndex; private final int mIdIndex; private final LayoutInflater mLayoutInflater; private final class ViewHolder { public TextView name; public ImageView image; public CheckBox checkBox; } public FriendAdapter(Context context, int layout, Cursor c, String[] from, int[] to) { super(context, layout, c, from, to); this.mContext = context; this.mLayout = layout; this.mCursor = c; this.mNameIndex = mCursor.getColumnIndex(WhipemDBAdapter.KEY_NAME); this.mIdIndex = mCursor.getColumnIndex(WhipemDBAdapter.KEY_FB_ID); this.mLayoutInflater = LayoutInflater.from(mContext); } public View getView(int position, View convertView, ViewGroup parent) { if (mCursor.moveToPosition(position)) { ViewHolder viewHolder; if (convertView == null) { convertView = mLayoutInflater.inflate(mLayout, null); viewHolder = new ViewHolder(); viewHolder.name = (TextView) convertView.findViewById(R.id.contact_name); viewHolder.image = (ImageView) convertView.findViewById(R.id.contact_pic); viewHolder.checkBox = (CheckBox) convertView.findViewById(R.id.checkbox); convertView.setTag(viewHolder); } else { viewHolder = (ViewHolder) convertView.getTag(); } String name = mCursor.getString(mNameIndex); String fb_id = mCursor.getString(mIdIndex); Drawable drawable = LoadImageFromWebOperations("http://graph.facebook.com/"+fb_id+"/picture"); boolean isChecked = ((GlobalVars) mContext.getApplicationContext()).isFriendSelected(fb_id); viewHolder.name.setText(name); viewHolder.image.setImageDrawable(drawable); viewHolder.checkBox.setTag(fb_id); viewHolder.checkBox.setChecked(isChecked); } return convertView; } 

这个例子几乎是正确的。 你不需要在newView()进行绑定,因为就像你提到的那样,将调用bindView() 。 如果你看到每个项目调用两次newView / bindView序列,你可能正在使用ListView ,其高度设置为wrap_content ,这总是一个坏主意。 最后, newView()bindView()特定于CursorAdapter :它实现了getView()并为您调用newView()bindView() 。 但是,重写getView()也是完全有效的。 这是其他适配器的工作方式。

请注意,仅对将在屏幕上显示的每个项目调用getView() (以及bindView / newView)。