LostNomad311
LostNomad311

Reputation: 2065

Custom ListView newView Issue

In short newView is not being called for each list item, here is log:

01-06 20:04:15.957: D/NoteListActivity(2771): newView Note ID:12
01-06 20:04:16.087: D/NoteItemView(2771): updateActionText Note ID:12 Action:Stamp
01-06 20:04:16.117: D/NoteListActivity(2771): bindView Note ID:12
01-06 20:04:16.329: D/NoteListActivity(2771): newView Note ID:13
01-06 20:04:16.477: D/NoteItemView(2771): updateActionText Note ID:13 Action:Stamp
01-06 20:04:16.497: D/NoteListActivity(2771): bindView Note ID:13
01-06 20:04:16.729: D/NoteListActivity(2771): newView Note ID:14
01-06 20:04:16.867: D/NoteItemView(2771): updateActionText Note ID:14 Action:Stamp
01-06 20:04:16.887: D/NoteListActivity(2771): bindView Note ID:14
01-06 20:04:17.107: D/NoteListActivity(2771): newView Note ID:15
01-06 20:04:17.247: D/NoteItemView(2771): updateActionText Note ID:15 Action:Stamp
01-06 20:04:17.269: D/NoteListActivity(2771): bindView Note ID:15
01-06 20:04:17.487: D/NoteListActivity(2771): newView Note ID:16
01-06 20:04:17.639: D/NoteItemView(2771): updateActionText Note ID:16 Action:Stamp
01-06 20:04:17.657: D/NoteListActivity(2771): bindView Note ID:16
01-06 20:04:17.897: D/NoteListActivity(2771): newView Note ID:17
01-06 20:04:18.007: D/dalvikvm(2771): GC_EXTERNAL_ALLOC freed 99K, 47% free 2902K/5447K, external 2888K/2971K, paused 53ms
01-06 20:04:18.127: D/NoteItemView(2771): updateActionText Note ID:17 Action:Count
01-06 20:04:18.147: D/NoteListActivity(2771): bindView Note ID:17
01-06 20:04:18.367: D/NoteListActivity(2771): newView Note ID:18
01-06 20:04:18.517: D/NoteItemView(2771): updateActionText Note ID:18 Action:Stamp
01-06 20:04:18.537: D/NoteListActivity(2771): bindView Note ID:18
01-06 20:04:36.488: W/KeyCharacterMap(2771): No keyboard for id 0
01-06 20:04:36.488: W/KeyCharacterMap(2771): Using default keymap: /system/usr/keychars/qwerty.kcm.bin
01-06 20:04:38.118: D/NoteListActivity(2771): newView Note ID:19
01-06 20:04:38.257: D/NoteItemView(2771): updateActionText Note ID:19 Action:Stamp
01-06 20:04:38.277: D/NoteListActivity(2771): bindView Note ID:19
01-06 20:04:38.767: D/NoteListActivity(2771): newView Note ID:20
01-06 20:04:38.849: D/NoteItemView(2771): updateActionText Note ID:20 Action:Stamp
01-06 20:04:38.867: D/NoteListActivity(2771): bindView Note ID:20
01-06 20:04:39.327: D/NoteItemView(2771): updateActionText Note ID:12 Action:Stamp
01-06 20:04:39.347: D/NoteListActivity(2771): bindView Note ID:21
01-06 20:04:39.857: D/dalvikvm(2771): GC_EXTERNAL_ALLOC freed 84K, 47% free 2944K/5511K, external 3593K/3852K, paused 59ms
01-06 20:04:39.997: D/NoteItemView(2771): updateActionText Note ID:13 Action:Stamp
01-06 20:04:40.017: D/NoteListActivity(2771): bindView Note ID:22
01-06 20:04:40.537: D/NoteItemView(2771): updateActionText Note ID:14 Action:Stamp
01-06 20:04:40.557: D/NoteListActivity(2771): bindView Note ID:23
01-06 20:04:41.087: D/NoteItemView(2771): updateActionText Note ID:15 Action:Stamp
01-06 20:04:41.107: D/NoteListActivity(2771): bindView Note ID:24
01-06 20:04:41.617: D/NoteItemView(2771): updateActionText Note ID:16 Action:Stamp
01-06 20:04:41.639: D/NoteListActivity(2771): bindView Note ID:25
01-06 20:06:23.858: D/NoteItemView(2771): updateActionText Note ID:18 Action:Stamp
01-06 20:06:23.878: D/NoteListActivity(2771): bindView Note ID:18
01-06 20:06:24.267: D/dalvikvm(2771): GC_EXTERNAL_ALLOC freed 79K, 47% free 2944K/5511K, external 4681K/4733K, paused 53ms
01-06 20:06:26.519: D/NoteItemView(2771): updateActionText Note ID:15 Action:Stamp
01-06 20:06:26.537: D/NoteListActivity(2771): bindView Note ID:17
01-06 20:06:26.927: D/dalvikvm(2771): GC_EXTERNAL_ALLOC freed 17K, 47% free 2944K/5511K, external 5020K/5295K, paused 60ms
01-06 20:06:26.987: D/NoteItemView(2771): updateActionText Note ID:12 Action:Stamp
01-06 20:06:27.008: D/NoteListActivity(2771): bindView Note ID:16
01-06 20:06:27.247: D/NoteItemView(2771): updateActionText Note ID:13 Action:Stamp
01-06 20:06:27.267: D/NoteListActivity(2771): bindView Note ID:15
01-06 20:06:27.517: D/NoteItemView(2771): updateActionText Note ID:14 Action:Stamp
01-06 20:06:27.537: D/NoteListActivity(2771): bindView Note ID:14
01-06 20:06:28.397: D/NoteItemView(2771): updateActionText Note ID:16 Action:Stamp
01-06 20:06:28.417: D/NoteListActivity(2771): bindView Note ID:13
01-06 20:06:28.809: D/NoteItemView(2771): updateActionText Note ID:19 Action:Stamp
01-06 20:06:28.837: D/NoteListActivity(2771): bindView Note ID:12
01-06 20:06:29.167: D/NoteItemView(2771): updateActionText Note ID:12 Action:Stamp
01-06 20:06:29.189: D/NoteListActivity(2771): bindView Note ID:16
01-06 20:06:29.477: D/NoteItemView(2771): updateActionText Note ID:15 Action:Stamp
01-06 20:06:29.497: D/NoteListActivity(2771): bindView Note ID:17
01-06 20:06:29.688: D/NoteItemView(2771): updateActionText Note ID:18 Action:Stamp
01-06 20:06:29.707: D/NoteListActivity(2771): bindView Note ID:18
01-06 20:06:31.807: D/NoteItemView(2771): updateActionText Note ID:20 Action:Stamp
01-06 20:06:31.827: D/NoteListActivity(2771): bindView Note ID:19
01-06 20:06:32.267: D/NoteItemView(2771): updateActionText Note ID:13 Action:Stamp
01-06 20:06:32.288: D/NoteListActivity(2771): bindView Note ID:20
01-06 20:06:32.537: D/NoteItemView(2771): updateActionText Note ID:14 Action:Stamp
01-06 20:06:32.567: D/NoteListActivity(2771): bindView Note ID:21
01-06 20:06:32.867: D/NoteItemView(2771): updateActionText Note ID:16 Action:Stamp
01-06 20:06:32.887: D/NoteListActivity(2771): bindView Note ID:22
01-06 20:06:33.127: D/NoteItemView(2771): updateActionText Note ID:19 Action:Stamp
01-06 20:06:33.147: D/NoteListActivity(2771): bindView Note ID:23
01-06 20:06:33.677: D/NoteItemView(2771): updateActionText Note ID:15 Action:Stamp
01-06 20:06:33.697: D/NoteListActivity(2771): bindView Note ID:24
01-06 20:06:34.187: D/NoteItemView(2771): updateActionText Note ID:14 Action:Stamp
01-06 20:06:34.207: D/NoteListActivity(2771): bindView Note ID:25
01-06 20:06:34.447: D/NoteItemView(2771): updateActionText Note ID:13 Action:Stamp
01-06 20:06:34.467: D/NoteListActivity(2771): bindView Note ID:21
01-06 20:06:34.647: D/NoteItemView(2771): updateActionText Note ID:20 Action:Stamp
01-06 20:06:34.667: D/NoteListActivity(2771): bindView Note ID:20
01-06 20:06:34.847: D/NoteItemView(2771): updateActionText Note ID:18 Action:Stamp
01-06 20:06:34.867: D/NoteListActivity(2771): bindView Note ID:19

And here is the adapter:

class NoteItemAdapter extends CursorAdapter {

    private LayoutInflater mInflater;

    public NoteItemAdapter(Context context, Cursor c) {
        super(context, c);
        mInflater = LayoutInflater.from(context);
    }

    public NoteItemAdapter(Context context, Cursor c, boolean autoRequery) {
        super(context, c, autoRequery);
        mInflater = LayoutInflater.from(context);
    }

    @Override
    public void bindView(View view, Context context, Cursor cursor) {
        final NoteListItemHolder noteItemHolder = (NoteListItemHolder)view.getTag();
        NoteCursor nc = (NoteCursor)cursor;

        initView(noteItemHolder, nc);

        Log.d(TAG, String.format("bindView Note ID:%s", nc.getColId()));
    }

    private void initView(final NoteListItemHolder noteItemHolder, NoteCursor nc)
            throws NotFoundException {
        noteItemHolder.getBase().setClickable(false);
        noteItemHolder.getBase().setLongClickable(true);
        noteItemHolder.getTopText().setText(nc.getColTitle());
        noteItemHolder.getBottomText().setText(nc.getColNote());
        byte[] icon = nc.getColActionIcon();
        if (icon != null) {
            noteItemHolder.getIconButton().setImageBitmap(BitmapUtil.BitmapFromByteArray(icon));
        } else {
            NoteAction actionType = NoteListItemHolder.NoteActionFromInt(nc.getColActionType());
            int actionIconResId = R.drawable.note_action_icon_none;
            switch (actionType) {
            case Span:
                actionIconResId = R.drawable.note_action_icon_span;
                break;
            case Stamp:
                actionIconResId = R.drawable.note_action_icon_stamp;
                break;
            case Count:
                actionIconResId = R.drawable.note_action_icon_count;
                break;
            default:
                //NOOP
                break;
            }
            noteItemHolder.getIconButton().setImageBitmap(((BitmapDrawable)getResources().getDrawable(actionIconResId)).getBitmap());
        }
        noteItemHolder.getIconButton().setClickable(true);
        noteItemHolder.getIconButton().setLongClickable(false);
        noteItemHolder.updateActionText();

        noteItemHolder.getIconButton().setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View iconView) {
                noteItemHolder.doAction();
            }
        });
    }

    @Override
    public View newView(Context context, Cursor cursor, ViewGroup viewGroup) {
        View row = mInflater.inflate(R.layout.note_list_item, viewGroup, false);
        NoteCursor nc = (NoteCursor)getCursor();
        NoteListItemHolder wrapper = new NoteListItemHolder(row, nc.getColId());
        row.setTag(wrapper);

        Log.d(TAG, String.format("newView Note ID:%s", nc.getColId()));

        return row;
    }
}

I've been reading a bunch about similar issues, and I just can't figure it out!

The first page of items (visible when the list view is loaded) are always correct, but when you scroll at least one of the text views of the list items is always correct and at least one is always wrong in the new items (both text views are getting their text updated from the bindView which is always called). This led me to believe that the issue was not in the adapter, but as the log shows, newView is not called for items 21 and up.

And... for an added bonus, when you scroll back up, the ones that were correct aren't anymore; they are now behaving like the rest of the list.

So, any ideas guys?

Upvotes: 0

Views: 290

Answers (2)

LostNomad311
LostNomad311

Reputation: 2065

So as @dmon pointed out, these views are being reused (yeah I know I should have gotten that concept by now). In my holders the note ID, among other things, was being stored and subsequently used to populate some of the sub-views. FYI I was in the process of otimizing these list items into the holder pattern, and thought why not put the text updates in there too since I'll have the data cached - then BOOM!

Now that I understand that the view does not always show the same data, I have removed that logic and everything is great!

Big thanks to @dmon for explaining this concept that I have failed to grasp (and hopefully this helps some other hopeless code monkey too)!

Here are the lines that changed (I am just passing the note ID to the holder now):

noteItemHolder.updateActionText();
//is now

noteItemHolder.updateActionText(noteID);

and

noteItemHolder.doAction();
//is now

noteItemHolder.doAction(noteID);

Upvotes: -1

dmon
dmon

Reputation: 30168

This is as expected. The CursorAdapter is simply recycling the views for you. newView() will only be called for the first screen (and maybe a couple of more items), but for all other views, the views you returned in newView() will be recycled and will only run through the bindView() method. The problem in these cases is usually that one of the fields is not returned to the "default" state and the stale data peeks through. That's why you have "incorrect" data. I can't see anything obviously wrong in the bindView() code you posted, but if I had to guess, I would say the problem is in the noteItemHolder.updateActionText() method.

Upvotes: 2

Related Questions