Droidman
Droidman

Reputation: 11608

android - custom ListView, getView method

alright, I voted to delete my previous similar question to keep it clean. The matter: I'm trying to use a custom ListView for displaying messages in a chat app. I now managed to set the text according to user's input but I have some troubles in the getView() method. You can see the problem at the pictures below: the inflated layouts are added at the wrong position.

enter image description here

This should start with test and end with test5. I suppose the getView() method should have been called 6 times since 6 rows were inflated? But I added a Log to this method and figured out that it was called like 20+ times! Why so?

enter image description here

My code goes below:

the adapter class:

public final class ChatAdapter extends BaseAdapter {
private Context context;
ViewHolder holder;

private ArrayList<String> messages;

public ChatAdapter(Context context, ArrayList<String> chat) {

    this.context = context;
    this.messages = chat;
    Log.d("ChatAdapter", "called constructor");

}

public int getCount() {
    return messages.size();
}

public Object getItem(int position) {
    return messages.get(position);
}

public long getItemId(int position) {
    return position;
}

public View getView(int position, View convertView, ViewGroup viewGroup) {

    if (convertView == null) {
        LayoutInflater inflater = (LayoutInflater) context
                .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        convertView = inflater.inflate(R.layout.row, null);

        holder = new ViewHolder();
        holder.message = (TextView) convertView
                .findViewById(R.id.tvMessage);
        holder.timestamp = (TextView) convertView.findViewById(R.id.tvTS);
        holder.indicator = (ImageView) convertView
                .findViewById(R.id.imgInd);

        String message = (String) getItem(position);
        holder.message.setText(message);
        holder.timestamp.setText(generateTimestamp());

        convertView.setTag(holder);

    } else {
        holder = (ViewHolder) convertView.getTag();

    }
    Log.d("ChatAdapter", "called getView");
    return convertView;
}

@SuppressLint("SimpleDateFormat")
public String generateTimestamp() {
    SimpleDateFormat sdf = new SimpleDateFormat("HH:mm");
    String ts = sdf.format(new Date());

    return ts;
}

public static class ViewHolder {
    public TextView message;
    public TextView timestamp;
    public ImageView indicator;
}

The ChatActivity:

public class ChatActivity extends ListActivity {

private EditText input;
private String tmpMessage;
ListView lv;
ChatAdapter adapter;
ArrayList<String> messages;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.lis);
    Button send = (Button) findViewById(R.id.btnSend);
    input = (EditText) findViewById(R.id.etInput);
    lv = getListView();

    messages = new ArrayList<String>();
    Log.d("Chat", "arrayList created");
    adapter = new ChatAdapter(this, messages);
    lv.setOnItemClickListener(new OnItemClickListener() {

        @Override
        public void onItemClick(AdapterView<?> arg0, View arg1, int arg2,
                long arg3) {
            // TODO
        }
    });

    lv.setAdapter(adapter);

    send.setOnClickListener(new View.OnClickListener() {

        @Override
        public void onClick(View v) {
            sendMessage();
        }
    });
}

public void sendMessage() {

    tmpMessage = input.getText().toString();
    input.setText("");


    messages.add(tmpMessage);

    adapter.notifyDataSetChanged();

}

What am I missing (except of some brain)? Any help is greatly appreciated.

Upvotes: 2

Views: 4793

Answers (1)

Sam
Sam

Reputation: 86948

I suppose the getView() method should have been called 6 times since 6 rows were inflated? But I added a Log to this method and figured out that it was called like 20+ times! Why so?

A common cause that forces getView() to be called multiple times is using wrap_content for the ListView's height.

Also this code in getView():

String message = (String) getItem(position);
holder.message.setText(message);
holder.timestamp.setText(generateTimestamp()); // You will need to make a permanent timestamp someday

Should be outside the if-else block to support scrolling.

Upvotes: 1

Related Questions