I am confused about how Android newView and getView in CursorAdapter work. Most of the implementations I have seen so far implement getView instead, however many online sources suggest that that is NOT the way to go, for example here.
My problem boils down to the following bits of code
@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);
}
Note that newView sets the layout (including left or right alignment of the image) while bindView sets the image (in this case blue or red). Thus, the expected behavior would be that all red squares be on the left and all blue squares on the right (since both color and position query the same ID-check on the cursor). Instead, I get the following layout:
Essentially, my issue is the same as in this question but I did not find any of the suggestions to solve my problem.
Thanks for any explanation to this weird behavior or solution to the problem!
By default, ListView
(and any other source that takes a CursorAdapter
tries to reuse views as often as possible.
Therefore newView()
is called only until enough views are created and after that, only bindView()
is called as you scroll down the list as it reuses the views it has already created.
If you have multiple view types (as it seems you do), you should also override getViewTypeCount() and getItemViewType(). These methods tell the adapter that only views of the same type should be reused, ensuring that your rows using listrow_chat_me
are only used for future listrow_chat_me
rows and not reused for listrow_chat_other
rows.
@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;
}
}