Why does getView return wrong convertView objects on BaseAdapter?
来源:互联网 发布:淘宝网男装休闲中山 编辑:程序博客网 时间:2024/06/04 00:56
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(); } @Override public int getCount() { return getContentCount() + (hasData ? 1 : 0); } private int getContentCount() { return Util.isEmpty(mData) ? 0 : mData.size(); } @Override public String getItem(int position) { if (getItemViewType(position) == TYPE_CONTENT) { return Util.isEmpty(mData) ? null : mData.get(position); } return null; } @Override public long getItemId(int position) { return position; } @Override public int getItemViewType(int position) { // 清除历史记录 if (hasData && getCount() - 1 == position) { return TYPE_CLEAR; } return TYPE_CONTENT; } @Override public int getViewTypeCount() { return TYPE_COUNT; } @Override public 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?
- 自定义BaseAdapter getView()方法内convertView.setTag(Object obj) ?
- BaseAdapter中的getview以及convertView的回收机制
- Android 重写BaseAdapter碰到getView中convertView出现错误
- BaseAdapter,getView
- BaseAdapter中重写getview的心得以及发现convertView回收的机制
- (柯昌合深入研究Android SimpleAdapter BaseAdapter 的getView(int position, View convertView, ViewGroup parent)
- BaseAdapter中重写getview的心得以及convertView回收的机制
- BaseAdapter中重写getview的心得以及发现convertView回收的机制
- BaseAdapter中重写getview的心得以及发现convertView回收的机制
- BaseAdapter中重写getview的心得以及发现convertView回收的机制
- BaseAdapter中重写getview的心得以及发现convertView回收的机制
- BaseAdapter中重写getview的心得以及发现convertView回收的机制
- BaseAdapter中重写getview的心得以及发现convertView回收的机制
- BaseAdapter中重写getview的心得以及convertView回收的机制
- BaseAdapter中重写getview的心得以及发现convertView回收的机制
- BaseAdapter中重写getview的心得以及发现convertView回收的机制
- BaseAdapter中重写getview的心得以及发现convertView回收的机制
- CMD一键获取 所有连接过的WIFI密码
- Java入门第三式
- Git 使用vi或vim命令打开、关闭、保存文件
- Advanced Programming in Unix Environment Episode 2
- jdk8 HotSpot内存模型
- Why does getView return wrong convertView objects on BaseAdapter?
- Note:C# Socket 连接域名
- 360安全卫士hookport.sys简单逆向——基础
- HTML中对VALUE属性的理解
- POJ 1991 Turning in Homework 区间DP
- LocalDB的使用详解
- <统计学习方法>5 逻辑斯蒂回归与最大熵模型
- CvMat,Mat和IplImage之间的转化和拷贝
- 嵌入式Linux驱动笔记(十二)------通俗易懂式分析了解spi框架