ListView的getView()获取位置异常,滚动时显示错误位置的解决方法
解决ListView滚动时Item位置偏移的问题
嘿,看了你的代码,问题根源就在ViewHolder的复用逻辑上——你漏了最关键的一步:把初始化好的ViewHolder绑定到View的Tag上,导致复用的时候拿不到正确的ViewHolder对象,进而出现滚动时数据绑定混乱、位置偏移的问题。
直接修复代码
修改ListAdapter里的getView方法,重点补全view.setTag(holder)这一步:
public View getView(int position , View view, ViewGroup parent ){ Log.d(TAG, "position=" + position); ViewHolder holder; // 先声明,不要每次都直接new if(view == null){ LayoutInflater inflater = context.getLayoutInflater(); view = inflater.inflate(R.layout.listview_chat_room_me,parent,false); holder = new ViewHolder(); // 只有当View是新创建时,才初始化ViewHolder holder.name_text = view.findViewById(R.id.txtName); holder.time_text = view.findViewById(R.id.txtTime); holder.message_text = view.findViewById(R.id.txtMessage); holder.image = view.findViewById(R.id.imgPersonalPhoto); view.setTag(holder); // 核心!把ViewHolder绑定到View的Tag上,方便后续复用 } else{ holder = (ViewHolder) view.getTag(); // 复用View时,直接从Tag取出对应的ViewHolder } try { holder.name_text.setText(list_name.get(position)); holder.time_text.setText(list_time.get(position)); holder.message_text.setText(list_message.get(position)); Glide.with(context).load(list_image.get(position)).into(holder.image); } catch (Exception e){ e.printStackTrace(); // 建议打印异常,别直接吞掉,方便排查问题 } return view; }
错误原因拆解
你原来的代码有两个明显问题:
- 每次调用
getView都先new一个ViewHolder,当View复用的时候,从Tag取的holder和你新new的holder冲突,而且第一次创建View时根本没把holder绑定到Tag上,view.getTag()拿到的是null,强制转换会抛出异常(你用try-catch掩盖了这个错误,导致数据没绑定成功) - 异常触发后数据绑定失效,再加上ListView的View复用机制,就会出现滚动时Item位置偏移、数据乱跳的情况
额外优化建议
你现在用四个ArrayList来存数据,维护起来很麻烦,建议自定义一个数据类封装所有字段:
public class ChatItem { private String name; private String time; private String message; private String imageUrl; public ChatItem(String name, String time, String message, String imageUrl) { this.name = name; this.time = time; this.message = message; this.imageUrl = imageUrl; } // 生成getter方法 public String getName() { return name; } public String getTime() { return time; } public String getMessage() { return message; } public String getImageUrl() { return imageUrl; } }
然后把Adapter改成继承ArrayAdapter<ChatItem>,这样只需要维护一个ArrayList<ChatItem>,在getView里直接通过ChatItem item = getItem(position)获取数据,代码更整洁,也不容易出错。
内容的提问来源于stack exchange,提问作者曾奕堯
相关产品推荐
相关产品推荐

