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

jul*_*jul 16 android simplecursoradapter

我从我找到的唯一一个例子中创建了一个自定义的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();
    }
}
Run Code Online (Sandbox Code Playgroud)

自定义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;
        }
    }

}
Run Code Online (Sandbox Code Playgroud)

dbm*_*dbm 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;
}
Run Code Online (Sandbox Code Playgroud)

  • 很好的答案,谢谢.但是,如果我们想在ImageView中添加onClick侦听器,我们应该怎么做?我在自定义适配器上添加了一个onClick(View v)方法,但它不起作用.任何提示? (2认同)

Rom*_*Guy 13

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

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