newView 和 bindView 的 CursorAdapter 不一致

CursorAdapter inconsistent between newView and bindView

我对 Android CursorAdapter 中的 newView 和 getView 的工作方式感到困惑。 到目前为止,我看到的大多数实现都是实现 getView 的,但是许多在线资源表明这不是可行的方法,例如 here.

我的问题归结为以下代码

@Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {

    // Decide if message was sent by Me or Other
    View chatRow;
    if(cursor.getInt(cursor.getColumnIndexOrThrow(DbChat.KEY_SENDER_ID)) == 0) {
        chatRow = LayoutInflater.from(context.getApplicationContext())
                     .inflate(R.layout.listrow_chat_me,parent,false);
    } else {
        chatRow = LayoutInflater.from(context.getApplicationContext())
                     .inflate(R.layout.listrow_chat_other,parent,false);
    }

    return chatRow;
}

@Override
public void bindView(View view, Context context, Cursor cursor) {

    TextView chatText = (TextView) view.findViewById(R.id.chat_text);
    ImageView imageView = (ImageView) view.findViewById(R.id.chat_img);

    chatText.setText(cursor.getString(cursor.getColumnIndexOrThrow(DbChat.KEY_TEXT)));

    if(cursor.getInt(cursor.getColumnIndexOrThrow(DbChat.KEY_SENDER_ID)) == 0) {
        imageView.setImageDrawable(ChatActivity.sIconBlue);
    } else {
        imageView.setImageDrawable(ChatActivity.sIconRed);
    }

请注意,newView 设置布局(包括图像的左对齐或右对齐),而 bindView 设置图像(在本例中为蓝色或红色)。 因此,预期的行为是所有红色方块都在左边,所有蓝色方块都在右边(因为颜色和位置都在光标上查询相同的 ID 检查)。 相反,我得到以下布局:

本质上,我的问题与此 question 中的问题相同,但我没有找到任何解决问题的建议。

感谢您对这种奇怪行为的任何解释或问题的解决方案!

默认情况下,ListView(以及任何其他采用 CursorAdapter 的来源会尝试尽可能多地重用视图。

因此 newView() 仅在创建足够的视图之前被调用,之后,只有 bindView() 在您向下滚动列表时被调用,因为它会重用已创建的视图。

如果您有多个视图类型(就像您看起来的那样),您还应该覆盖 getViewTypeCount() and getItemViewType()。这些方法告诉适配器只应重用相同类型的视图,确保使用 listrow_chat_me 的行仅用于将来的 listrow_chat_me 行,而不是用于 listrow_chat_other 行。

@Override
public int getViewTypeCount() {
  return 2;
}

@Override
public int getItemViewType(int position) {
  // getItem(position) returns a Cursor at the given position
  Cursor cursor = (Cursor) getItem(position);
  if (cursor.getInt(cursor.getColumnIndexOrThrow(DbChat.KEY_SENDER_ID)) == 0) {
    return 0;
  } else {
    return 1;
  }
}

默认情况下,游标适配器仅采用一种行布局并根据行类型重用视图,这就是为什么您在左侧看到子项的原因。

有两种选择:使用一个视图并在绑定时适当地隐藏注释,或者研究重写方法

 getItemViewType(int position)

 getViewTypeCount()