-1

I've a listview that mixs its items when i scroll it. This is my code:

public class ListView_MessagesAdapter extends BaseAdapter {
private List<Message> messages;

public ListView_MessagesAdapter(List<Message> messages) {
    this.messages = messages;
}

@Override
public int getCount() {
    return this.messages != null ? this.messages.size() : 0;
}

@Override
public Message getItem(int i) {
    return this.messages != null ? this.messages.get(i) : null;
}

@Override
public long getItemId(int i) {
    return this.messages != null ? i : -1;
}

@Override
public View getView(int i, View view, ViewGroup viewGroup) {
    if (view == null)
        view = (RelativeLayout) LayoutInflater.from(this.context).inflate(R.layout.listview_messages, viewGroup, false);

    Message message = this.getItem(i);

    if (message != null) {
        switch (message.type) {
            case DEFAULT:
                this.manageAsDefault(view, message);
                break;
            case TEXT:
                this.manageAsText(view, message);
                break;
            case AUDIO:
                this.managerAsAudio(view, message);
                break;
        }
    }

    return view;
}

private void manageAsDefault(View view, Message message) {
    // Manage message...
}

private void manageAsText(View view, Message message) {
    // Manage message...
}

private void managerAsAudio(View view, Message message) {
    // Manage message...
}

}

And this is how i bind the listview:

ListView_MessagesAdapter adapter = new ListView_MessagesAdapter(messages); lstMessages.setAdapter(adapter);

I bind the listview with 20 messages in a specific order. It loads correctly the first time but, when i scroll, the items are being mixed without any sense.

Any solutions that i've found on web seems work. Any solution?

Sirolol
  • 77
  • 9

1 Answers1

0

In getView() you first need to reset the state of the view variable. This is because it is re-used when you scroll, causing, for example, a view that was handled as text to be handled as audio.

Try doing view.removeAllChildren() (or something like that).

Minas Mina
  • 2,058
  • 3
  • 21
  • 35
  • Doing a reset of the view, it losts the view's state (for example the audio's reprodution state). Also, i think that reset a view is not a good practise in general. – Sirolol Jan 24 '18 at 14:45
  • @Loris Did that fix the original issue, the mixing of the items? – Minas Mina Jan 24 '18 at 14:46
  • Yes, but generate a cascade of other problems: for example, images need to be reloaded, same for audio. This is a workaround that corrects a problem but creates other 10. It's not the right way – Sirolol Jan 24 '18 at 14:51
  • @Loris Well at least you know what the problem was :) In general, when using an adapter like this (and `RecyclerView` as well), this is the way it needs to be done. If you use `Glide` for loading the images it will cache them automatically, As for the audio, you can store the audio references in your class in a `Map` and then get it by an ID when binding the view. – Minas Mina Jan 24 '18 at 14:57
  • I've migrated to RecyclerView to check if i've using a bad approach: the result is the same. – Sirolol Jan 24 '18 at 15:37
  • @Loris It's the same because that's how they work. They assume that the UI will be _reset_ in `onBindViewHolder()`. For example, if you had a single `TextView` that you make visible / invisible depending on some condition, in `onBindViewHolder()` you would need to reset the visibility (set it to visible), decide again if it needs to be visible / invisible and set the visibility accordingly. In your case you have something more complex, but the philosophy is the same. – Minas Mina Jan 24 '18 at 16:08