我从the only example I found之一创建了一个自定义SimpleCursorAdapter。
调用ListActivity时,会为每个数据库条目调用newView和bindView,并为每个条目再次调用。我有几个问题:
- 这是正确的例子(如果没有,我在哪里可以找到一个)?
-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<String> 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;
}
}
}
答案 0 :(得分:21)
覆盖getView()
功能使您可以“重新使用”已经膨胀的列表项(当您在列表中来回滚动时,从当前视图端口“滚出”的列表项)。
通过这样做,您将节省大量内存资源和处理器运行时间,因为充气是一项非常耗时的操作。对于您重复使用的每个convertView
,您还可以保存GC运行时(因为垃圾收集器不必收集该特定列表项)。
您还可以创建一个“视图集合”类(以下示例中的ViewHolder
类),该类将保存充气列表项中每个视图的引用。这样,您不必每次使用新值更新列表项时都找到它们(通常不会滚动列表)。 findViewById()
也是一项相当耗时的操作。
此外,我认为您可以缓存更多变量,例如布局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;
}
答案 1 :(得分:13)
这个例子几乎是正确的。您不需要在newView()
中执行绑定,因为正如您所提到的,bindView()
将被调用。如果你看到每个项目调用两次newView / bindView序列,你可能正在使用ListView
,其高度设置为wrap_content
,这总是一个坏主意。最后,newView()
和bindView()
特定于CursorAdapter
:它实施getView()
并为您调用newView()
或bindView()
。但是,覆盖getView()
也是完全有效的。这就是其他适配器的工作方式。
请注意,getView()
(以及bindView / newView)仅针对将在屏幕上显示的每个项目调用。