2 xkenqq xkenqq 于 2016.03.14 16:15 提问

android 关于listview convertview的一些问题,求解!

图片说明
做的是一个聊天界面,这是adapter代码。
运行时只能输入一次,输第二次时,参数convertview是第二次view的对象,不知道为什么啊。

 package com.example.chattest;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;

import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.Window;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ListView;

public class ChatActivity extends Activity implements OnClickListener {
    private Button btnSend;
    private ListView lvChat;
    private EditText etSendContent;
    //聊天内容的适配器
    private ChatMsgViewAdapter chatMsgAdapter;
    //聊天内容
    private List<ChatMsgInfo> chatMsgDataArrays = new ArrayList<ChatMsgInfo>();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        //不显示标题栏
        requestWindowFeature(Window.FEATURE_NO_TITLE); 
        setContentView(R.layout.chat);
        initView();
        initData();
    }

    //初始化视图
    private void initView() {
        lvChat = (ListView) findViewById(R.id.chat_listview);
        btnSend = (Button) findViewById(R.id.btn_send);
        btnSend.setOnClickListener(this);
        etSendContent = (EditText) findViewById(R.id.et_sendmessage); 
    }


    //聊天数据
    //private final static int COUNT = 10
    private String text = new String("第1种写法果然最慢,第二种写法由于用了StringBuffer,快了很多。奇怪的是"
            + "第4种写法竟然也很快,比用StringBuffer还快,怎么回事?其实慢,第二种写"
            + "法由于用了StringBuffer,快了很多。奇怪的是第4种写法竟然也很快,比用StringBuffer还快,怎"
            + "比用StringBuffer还快,怎么回事?其r还快,怎么回事?其回事?其如果你调试过字符串连接的执行过程就会知");
    private String date = new String("2016-3-10 18:11");

    //初始化数据
    private void initData() {
        ChatMsgInfo msgExample = new ChatMsgInfo("XiaoMing", date, text, true);
        chatMsgDataArrays.add(msgExample);
        chatMsgAdapter = new ChatMsgViewAdapter(this, chatMsgDataArrays);
        //listview绑定adapter
        lvChat.setAdapter(chatMsgAdapter);
    }

    @Override
    public void onClick(View v) {
        // TODO Auto-generated method stub
        switch(v.getId()) {
        case R.id.btn_send:
            send();
            break;
        }
    }

    //发送按钮的响应函数
    private void send() {
        //获取输入文本框内容
        String sendContent = etSendContent.getText().toString(); 
        if (sendContent.length() > 0) {
            ChatMsgInfo msg = new ChatMsgInfo("XiaoHong", getDate(), sendContent, false);
            chatMsgDataArrays.add(msg);
            //通过一个外部的方法控制如果适配器的内容改变时需要强制调用getView来刷新每个Item的内容。
            Log.d("chattest", "after setchanged!");
            chatMsgAdapter.notifyDataSetChanged();
            etSendContent.setText("");
            //定位到最后一行
            Log.d("chattest", "after setSelection!");
            lvChat.setSelection(lvChat.getCount() -1 );
        }
    }


    //获取时间
    private String getDate() {
        Calendar c = Calendar.getInstance();
        String year = String.valueOf(c.get(Calendar.YEAR));
        String month = String.valueOf(c.get(Calendar.MONTH));
        String day = String.valueOf(c.get(Calendar.DAY_OF_MONTH) + 1);
        String hour = String.valueOf(c.get(Calendar.HOUR_OF_DAY));
        String mins = String.valueOf(c.get(Calendar.MINUTE));
        StringBuffer buffer = new StringBuffer();
        buffer.append(year + "-" + month + "-" + day + " " + hour + ":" + mins);
        return buffer.toString();
    }
}
 package com.example.chattest;

import java.util.List;

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;

public class ChatMsgViewAdapter extends BaseAdapter {
    private static final int TYPE_COM_MSG = 0;
    private static final int TYPE_TO_MSG = 1;
    //private static final int TAG_KEY_ITEM_TYPE = 0;
    //private static final int TAG_KEY_VIEWHOLDER = 1;

    private List<ChatMsgInfo> data;//数据list
    private LayoutInflater myInflater;//layout convert view对象
    private Context context;//环境

    //构造
    public ChatMsgViewAdapter(Context context, List<ChatMsgInfo> data) {
        this.context = context;
        this.data = data;
        myInflater = LayoutInflater.from(context);
    }

    @Override
    public int getItemViewType(int position) {
        // TODO Auto-generated method stub
        ChatMsgInfo msg = data.get(position);
        if (msg.getMsgType()) {
            return TYPE_COM_MSG;
        } else {
            return TYPE_TO_MSG;
        }
    }

    @Override
    public int getViewTypeCount() {
        // TODO Auto-generated method stub
        return 2;
    }

    //获取ListView的个数
    @Override
    public int getCount() {
        return data.size();
    }

    //获取项
    @Override
    public Object getItem(int position) {
        return data.get(position);
    }

    //获取项的id
    @Override
    public long getItemId(int position) {
        return position;
    }

    //获取view
    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        ChatMsgInfo chatMsg = data.get(position);//聊天数据
        boolean isComMsg = chatMsg.getMsgType();//数据类型(发送、接收)
        LeftItemViewHolder leftViewHolder = null;
        RightItemViewHolder rightViewHolder = null;
        int viewType = getItemViewType(position);
        System.out.println(position + " " + convertView);

        if (convertView == null || ((Integer)convertView.getTag(R.id.tag_item_viewtype)) != viewType) {
            //区分消息类别,展示不同的界面
            if (viewType == TYPE_COM_MSG) {
                convertView = myInflater.inflate(R.layout.chat_msg_text_left_item, null);
                leftViewHolder = new LeftItemViewHolder();
                leftViewHolder.tvSendTime = (TextView) convertView.findViewById(R.id.tv_sendtime);
                leftViewHolder.tvUserName = (TextView) convertView.findViewById(R.id.tv_username);
                leftViewHolder.tvContent = (TextView) convertView.findViewById(R.id.tv_chatcontent);
                leftViewHolder.isComMsg = isComMsg;
                convertView.setTag(R.id.tag_item_viewholder, leftViewHolder);
            } else {
                convertView = myInflater.inflate(R.layout.chat_msg_text_right_item, null);
                rightViewHolder = new RightItemViewHolder();
                rightViewHolder.tvSendTime = (TextView) convertView.findViewById(R.id.tv_sendtime);
                rightViewHolder.tvContent = (TextView) convertView.findViewById(R.id.tv_chatcontent);
                rightViewHolder.isComMsg = isComMsg;
                convertView.setTag(R.id.tag_item_viewtype, rightViewHolder);
            }
            convertView.setTag(R.id.tag_item_viewtype, viewType);

        } else {
            if (viewType == TYPE_COM_MSG) {
                leftViewHolder = (LeftItemViewHolder) convertView.getTag(R.id.tag_item_viewholder);
            } else {
                rightViewHolder = (RightItemViewHolder) convertView.getTag(R.id.tag_item_viewholder);
            }
        }

        if (viewType == TYPE_COM_MSG) {
            leftViewHolder.tvUserName.setText(chatMsg.getName());
            leftViewHolder.tvSendTime.setText(chatMsg.getDate());
            leftViewHolder.tvContent.setText(chatMsg.getText());
        } else {
            rightViewHolder.tvSendTime.setText(chatMsg.getDate());
            rightViewHolder.tvContent.setText(chatMsg.getText());
        }

        System.out.println(position + " " + convertView);
        return convertView;

    }

    //保存项,显示项的内容
    static class LeftItemViewHolder {
        public TextView tvSendTime;
        public TextView tvUserName;
        public TextView tvContent;
        public boolean isComMsg = true;
    }

    static class RightItemViewHolder {
        public TextView tvSendTime;
        public TextView tvContent;
        public boolean isComMsg = true;
    }
}

5个回答

sjwjay
sjwjay   2016.03.14 16:26

这种问题,一般都是出在适配器上面,你是不是代码贴错了

sjwjay
sjwjay   2016.03.14 16:27

这种问题,一般都是出在适配器上面,你是不是代码贴错了

luochoudan
luochoudan   Ds   Rxr 2016.03.14 17:15

把这句删了试试 ?
convertView.setTag(R.id.tag_item_viewtype, viewType);

xkenqq
xkenqq 为什么我看到的很多例子,复用convert都没有类型判断啊,难道不需要吗?
2 年多之前 回复
xkenqq
xkenqq
2 年多之前 回复
xkenqq
xkenqq 为什么要删除这句话
2 年多之前 回复
lly4321lly
lly4321lly   2016.03.14 18:11

这句什么意思?『运行时只能输入一次,输第二次时,参数convertview是第二次view的对象』是没复用的意思吗?前两次当然不会复用
前面都setTag了,还要这句干嘛?『convertView.setTag(R.id.tag_item_viewtype, viewType);』删掉

lxk_1993
lxk_1993   Rxr 2016.03.14 18:25

if (convertView == null || ((Integer)convertView.getTag(R.id.tag_item_viewtype)) != viewType) {
//区分消息类别,展示不同的界面
if (viewType == TYPE_COM_MSG) {
convertView = myInflater.inflate(R.layout.chat_msg_text_left_item, null);
leftViewHolder = new LeftItemViewHolder();
leftViewHolder.tvSendTime = (TextView) convertView.findViewById(R.id.tv_sendtime);
leftViewHolder.tvUserName = (TextView) convertView.findViewById(R.id.tv_username);
leftViewHolder.tvContent = (TextView) convertView.findViewById(R.id.tv_chatcontent);
leftViewHolder.isComMsg = isComMsg;
convertView.setTag(R.id.tag_item_viewholder, leftViewHolder);
} else {
convertView = myInflater.inflate(R.layout.chat_msg_text_right_item, null);
rightViewHolder = new RightItemViewHolder();
rightViewHolder.tvSendTime = (TextView) convertView.findViewById(R.id.tv_sendtime);
rightViewHolder.tvContent = (TextView) convertView.findViewById(R.id.tv_chatcontent);
rightViewHolder.isComMsg = isComMsg;
convertView.setTag(R.id.tag_item_viewtype, rightViewHolder);
}
convertView.setTag(R.id.tag_item_viewtype, viewType);

                    这里的最后一句删掉
Csdn user default icon
上传中...
上传图片
插入图片
准确详细的回答,更有利于被提问者采纳,从而获得C币。复制、灌水、广告等回答会被删除,是时候展现真正的技术了!
其他相关推荐
Android性能:经典ListView适配器convertView缓存及复用机制
Android性能:经典ListView适配器convertView缓存及复用机制Android中的ListView常用Adapter中都会涉及到convertView的使用,使用convertView主要是为了缓存试图View,用以增加ListView的item view加载效率。有经验的Android开发者通常知道在Adapter的getView中,先判断convertView是否为空null
ListView的优化之复用convertView和利用ViewHolder
ListView的优化之复用convertView和利用ViewHolder
ListView中ConvertView和ViewHolder
ListView中ConvertView和ViewHolder
listView的convertView复用机制
listView的convertView复用机制1、convertView的数量=屏幕item数量+item样式数量*1; 2、listView对convertView回收,根据getItemType(position)获取item样式数量,然后创建一个数组,元素为list集合,数组长度刚好为Item样式数量(这也是为什么item样式只能从零开始定义的原因); 3、convertView复用时,
android Listview的getView和convertview原理解析以及使用不同的item布局(二)
博主工作了几年,也用了几年的ListView等AdapterView控件,但关于Adapter的一些问题并没有深入下去,终于有时间学习总结下关于BaseAdapter的一些较深入的话题。本文涉及三个话题:Adapter的回收机制和效率提升,getItemViewType()/getViewTypeCount()方法以及notifyDatasetChanged()使用的注意点。 1.Adapt
ListView中convertView只有第一次为null的原因
ListView             android:id="@+id/result"             android:layout_width="fill_parent"             android:layout_height="fill_parent"/> 此处请注意,ListView的android:layout_height属性值为"fill_paternt
android Listview的getView和convertview原理解析(三)
以前一直在用BaseAdapter,对于其中的getview方法的重写一直不太清楚。今天终于得以有空来探究它的详细机制。 下面先讲讲我遇到的几个问题: 一.View getview(int position, View convertview, ViewGroup parent )中的第二个参数是什么含义; 二.View的SetTag和getTag方法的用途; 先来解决第一个问题: an
ListView优化之一:重用convertView
【ListView优化方式有多种多样,而我们本文作为ListView优化系列文章的第一篇文章,欢迎大家持续关注ListView优化系列文章并关注Jimy的博客。有误的地方,希望大家能多多指正。】 ListView优化之一:重用convertView 重用convertVIew,很大程度上减少了Android设备内存的消耗。 (通过判断convertView是否为null,是的话就需要产生一个
convertView,这个是Android在为我们而做的缓存机制。
ListView与Adapter使用要点 博客分类:  Android   项目用到ListView,由于要用到 ImageView ,图片源不是在资源里面的,没法使用资源 ID,因此无法直接使用SimpleAdapter,要自己写一个Adapter。 在使用ListView和Adapter需要注意以下几点:   1. Adapter.getView()
LayoutInflater的inflate方法引起的listview界面布局问题
今天,看到了一篇文章讲LayoutInflater的用法,瞬间感觉自己对这个类确实不够了解。 我们最常用的便是LayoutInflater的inflate方法,这个方法重载了四种调用方式,分别为: 1. public View inflate(int resource, ViewGroup root) 2. public View inflate(int resource