ListView 加载两种不同类型的layout,自定义adapter,重写了getItemViewType和getViewTypeCount方法,代码如下:

class ContentAdapter extends BaseAdapter {private Context mContext;private List<String> mData;/*** 内容列表*/private static final int TYPE_CONTENT = 0;/*** 清除记录*/static final int TYPE_CLEAR = 1;/*** 类型总数*/private static final int TYPE_COUNT = 2;private boolean hasData;public ContentAdapter(Context context) {mContext = context;}public void setData(List<String> data) {mData = data;hasData = Util.isEmpty(data) ? false : true;notifyDataSetChanged();}@Overridepublic int getCount() {return getContentCount() + (hasData ? 1 : 0);}private int getContentCount() {return Util.isEmpty(mData) ? 0 : mData.size();}@Overridepublic String getItem(int position) {if (getItemViewType(position) == TYPE_CONTENT) {return Util.isEmpty(mData) ? null : mData.get(position);}return null;}@Overridepublic long getItemId(int position) {return position;}@Overridepublic int getItemViewType(int position) {// 清除历史记录if (hasData && getCount() - 1 == position) {return TYPE_CLEAR;}return TYPE_CONTENT;}@Overridepublic int getViewTypeCount() {return TYPE_COUNT;}@Overridepublic View getView(final int position, View convertView, ViewGroup parent) {ItemHolder holder = null;int type = getItemViewType(position);if (type == TYPE_CLEAR) {if (convertView == null) {convertView = LayoutInflater.from(mContext).inflate(R.layout.layout_clear_item, parent, false);new ClearItemHolder(convertView);}} else {if (convertView == null) {convertView = LayoutInflater.from(mContext).inflate(R.layout.layout_item, parent, false);holder = new ItemHolder(convertView);convertView.setTag(holder);} else {holder = (ItemHolder) convertView.getTag();}}if (type == TYPE_CONTENT) {if (holder != null && position < mData.size()) {String message = getItem(position);holder.bindData(message, position);}}return convertView;}class ItemHolder {TextView itemTv;private String message;private int position;public ItemHolder(View rootView) {// ...}public void bindData(String message, int position) {// ...}}class ClearItemHolder {TextView itemTv;public ClearItemHolder(View rootView) {// ...}}}

看代码没有任何问题,但是每次动态的往data中添加一个元素时,调用setData方法刷新ListView,这是会调用多次adapter.getView方法.
显示出来的效果是“清除历史记录”会被多次添加

通过排查代码,断点都没有找出原因,data数据也是正常的。
只能用最原始的重要的位置输出日志:
在getView给两种类型的convertView设置id,然后输出:

public View getView(final int position, View convertView, ViewGroup parent) {if (type == TYPE_CLEAR) {converView.setId(1000);} else {converView.setId(1001);}Log.d(TAG, "converView:" + converView.getId() + ", position:" + position + ", type:" + type + ", message:"+message);return convertView;}

通过日志输出发现最后一次调用getView方法,getCount-2 这行的converView ID(1001)被修改成“清除”layout的converView ID(1000) ,其他输出都是正常。

很诡异的问题,在stackoverflow找到类似问题
https://stackoverflow.com/questions/12018997/why-does-getview-return-wrong-convertview-objects-on-separatedlistadapter

原因:

The recycle bin technically stores the convert views based on the type that was initially read from getItemViewType but is then saved to the view’s LayoutParams object. If you overwrite the view’s LayoutParams you will overwrite the view type and thus break the recycling

重新设置LayoutParams导致某些类型丢失,从而导致converView获取错乱。

修复

在getView在判null基础上,对不同类型加一个tag判断

public View getView(final int position, View convertView, ViewGroup parent) {if (type == TYPE_CLEAR) {if (convertView == null) {convertView = xxx;new ClearItemHolder(convertView);}} else {if (convertView == null || !(convertView.getTag() instanceof ItemHolder)) {convertView = xxx;convertView.setTag(holder);} else {holder = (ItemHolder) convertView.getTag();}}// ....return convertView;}

Why does getView return wrong convertView objects on BaseAdapter?相关推荐

  1. android 之自定义适配器(重写的getView()方法中convertView元素的妙用)一个实例

    实现效果: 主要还是ListView的优化: 基本思路: <1>使用自定义适配器完成操作 <2>将listView进行优化处理 /*  //ListView完成了重用条目的优化 ...

  2. ListView的性能优化之convertView和viewHolder

    ListView优化大致从以下几个角度: 1.复用已经生成的convertView: 2.添加viewHolder类: 3.缓存数据(图片缓存): 4.分页加载. 一.复用convertView 首先 ...

  3. java对象比较 hashcode_Java Objects.hash()与自己实现的hashCode()比较

    Java 7新增了Objects类,它为对象提供了一些便捷的静态方法,如equals(),hashCode(),hash(),compare(),toString()等等. 这里比较一下Objects ...

  4. getView的解析流程

    public Map<Long,QuorumPeer.QuorumServer> getView() { return Collections.unmodifiableMap(this.q ...

  5. 【Java】java.util.Objects 工具类方法研究

    [Java]java.util.Objects 工具类方法研究 Objects 与 Object 区别 Object 是 Java 中所有类的基类,位于java.lang包. Objects 是 Ob ...

  6. n-null is null: method kotlin.jvm.internal.Intrinsics.checkParameterIsNotNull, parameter convertView

    我这是把java转kotlin,报错提示: java.lang.IllegalArgumentException: Parameter specified as non-null is null: m ...

  7. android Adapter使用详解

    将此句说100遍, 你就会用了: 适配器的作用就是将数据绑定到条目界面的每一个显示控件上. ---------------------------------屎一样的分割线-------------- ...

  8. ListView中含有EditText时候--要命的焦点问题迎刃而解

    最近做项目的时候遇到了一个问题,就是在ListView的item上面含有一个EditText,要求是这样:1当点击item的时候,item可以点击;2当点击EditText的时候EditText也可以 ...

  9. 如何使用Retrofit,OkHttp,Gson,Glide和Coroutines处理RESTful Web服务

    Kriptofolio应用程序系列-第5部分 (Kriptofolio app series - Part 5) These days almost every Android app connect ...

  10. Android内存泄漏分析及调试

    2019独角兽企业重金招聘Python工程师标准>>> Android内存泄漏分析及调试 分类: Android2013-10-25 11:31 5290人阅读 评论(5) 收藏 举 ...

最新文章

  1. Asp.net Core认证和授权:JWT认证和授权
  2. Hadoop权威指南阅读笔记
  3. poj 2516 最小费用最大流
  4. Matlab内置的矩阵反转函数
  5. 信息检索及DM必备知识总结:luncene
  6. matlab设置随机流的种子
  7. 如何保证添加自定义对象元素的唯一性
  8. 三星Galaxy Z海报曝光 采用双铰链三折叠设计
  9. 第3章2节《MonkeyRunner源码剖析》脚本编写示例: MonkeyDevice API使用示例(原创)
  10. python 字符编码、格式化
  11. UVA11554 Hapless Hedonism【数学计算+大数】
  12. 机器学习--支持向量机(六)径向基核函数(RBF)详解
  13. 持续集成并不能消除 Bug,而是让它们非常容易发现和改正(转)
  14. 【用matlab设计仿真数字锁相放大器】
  15. MongoDB 数据库基本操作
  16. vmware创建win7虚拟机
  17. redisson 主从模式Unsupported protocol version 50_强推七本欢喜冤家甜文,男女主从互怼到互宠,超甜超撩超过瘾!...
  18. HUAWEI 机试题:工厂流水线调度
  19. 华为eNSP 配置DHCP自动分配IP地址
  20. Kahan's summation Formula

热门文章

  1. html水平制表和垂直制表,将水平制表符转换为垂直制表符(仅限HTML和CSS,无js)
  2. 简单的解决idea tomcat run正常debug报错
  3. EPPlus.Core 1.5.4 报错 font '?' cannot be found docker core运行时2.1.0 alpine镜像 缺失微软字体...
  4. 如何学习Vim(转)
  5. Entity Framework 4.1 Code First学习之路(二)
  6. asp.net定时自动执行控制台程序
  7. 获取Repeater控件里动态声称的控件的值
  8. violate、内存屏障
  9. Spring Cloud Eureka服务注册中心 多节点搭建(学习总结)
  10. @Value竟然能玩出这么多花样,涨知识了