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

发布于 2024-10-20 10:35:34 字数 5127 浏览 3 评论 0原文

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

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

- 这个例子正确吗(如果不对,我在哪里可以找到)?

-如果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;
        }
    }

}

I created a custom SimpleCursorAdapter from one of the only example I found.

When my ListActivity is called, newView and bindView are called for every of my DB entry, and called again for every entry. I've got a few questions:

-is the example right (if not, where can I find one)?

-if bindView call is always preceded by newView call, why doing the same in both functions?

-why is the sequence newView-bindView called twice for every item?

-why some CursorAdapter examples use getView instead of newView and bindView?

Basically, how should SimpleCursorAdapter be used, and what's wrong with my code?

Thanks


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();
    }
}

Custom 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;
        }
    }

}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

无妨# 2024-10-27 10:35:34

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

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

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

另外,我认为您可以缓存更多变量,例如布局充气器和列索引。一切都是为了节省时间:-)

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;
}

Overriding the getView() function gives you the possibility of "re-using" already inflated list items (the list items that are "scrolled out" from the current view port when you scroll your list back and forth).

By doing so you'll save a lot of memory resources and processor run time, since inflating is a quite time consuming operation. For each and every convertView you re-use you also save GC run-time (since the garbage collector doesn't have to collect that specific list item).

You can also create a "view collection" class (the ViewHolder class in the below example) which will hold the references for each view in your inflated list item. This way you don't have to find them each and every time you update a list item with new values (typically whan you scroll the list). findViewById() is also a rather time consuming operation.

Also I think you can cache more variables, like the layout inflater, and the column indices. Everything to save time :-)

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;
}
三生池水覆流年 2024-10-27 10:35:34

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

请注意,仅针对将在屏幕上显示的每个项目调用 getView() (因此还有 bindView/newView)。

The example is almost right. You don't need to do the binding in newView(), since like you mentioned, bindView() will be called. If you see the sequence newView/bindView called twice per item, you are probably using ListView with its height set to wrap_content, which is always a bad idea. Finally, newView() and bindView() are specific to CursorAdapter: it implements getView() and calls either newView() or bindView() for you. However, overriding getView() is perfectly valid as well. This is how other adapters work.

Note that getView() (and therefore bindView/newView) are only invoked for each item that will be displayed on the screen.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文