ListView数据错位问题

今天同事做一个发送语音的功能,发现点击语音播放的时候,实际播放语音的喇叭不是点击的那个,而是跳到别的地方了,他的代码如下

	public View getView(int position, View convertView, ViewGroup parent) {
		ChatMsgEntity entity = coll.get(position);
		boolean isComMsg = entity.getMsgType();
		LayoutInflater mInflater  = (LayoutInflater)context
                .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
		ViewHolder viewHolder=null;
		if (convertView == null) {
			if (isComMsg) {
				convertView = mInflater.inflate(
						R.layout.chatting_item_msg_text_left, null);
			} else {
				convertView = mInflater.inflate(
						R.layout.chatting_item_msg_text_right, null);
			}

			viewHolder = new ViewHolder();
			viewHolder.tvSendTime = (TextView) convertView
					.findViewById(R.id.tv_sendtime);
			viewHolder.tvUserName = (TextView) convertView
					.findViewById(R.id.tv_username);
			viewHolder.tvContent = (TextView) convertView
					.findViewById(R.id.tv_chatcontent);
			viewHolder.icon = (ImageView) convertView
					.findViewById(R.id.iv_userhead);
			viewHolder.chatPic = (ImageView) convertView
					.findViewById(R.id.chat_img);
			viewHolder.isComMsg = isComMsg;

			convertView.setTag(viewHolder);
		} else {
			viewHolder = (ViewHolder) convertView.getTag();
		}
		final String mass = entity.getMessage();
		OnClickListener listener = new View.OnClickListener() {

			@Override
			public void onClick(View arg0) {
				// TODO Auto-generated method stub
				if (mass.contains("/storage/")&&mass.endsWith(".jpg")) {

					}else if (mass.contains("/storage/")&&mass.endsWith(".amr")) {
						if (judgeAnmi) {
							ad.start();
							judgeAnmi = !judgeAnmi;
						}else {
							ad.stop();
							judgeAnmi = !judgeAnmi;
						}

					}
				}
		};
		viewHolder.tvSendTime.setText(entity.getDate());
		viewHolder.tvUserName.setText(entity.getName());

		if (mass.contains("/storage/")&&mass.endsWith(".jpg")) {
			Bitmap bm = convertToBitmap(entity.getMessage(),200,200);
			BitmapDrawable bd = new BitmapDrawable(bm);
			viewHolder.chatPic.setBackgroundDrawable(bd);
			viewHolder.tvContent.setText("");
		}else if(mass.contains("/storage/")&&mass.endsWith(".amr")){
			viewHolder.chatPic.setBackgroundResource(R.anim.voice_muti);
			ad = (AnimationDrawable) viewHolder.chatPic.getBackground();

			viewHolder.tvContent.setText(mass.substring(0, mass.indexOf("/"))+"″");
		}else {
			viewHolder.tvContent.setText(mass);
			viewHolder.chatPic.setBackgroundDrawable(null);

		}
		viewHolder.chatPic.setOnClickListener(listener);
		return convertView;
	}

先看看google官方demo的写法

  public View getView(int position, View convertView, ViewGroup parent) {
            // A ViewHolder keeps references to children views to avoid unneccessary calls
            // to findViewById() on each row.
            ViewHolder holder;

            // When convertView is not null, we can reuse it directly, there is no need
            // to reinflate it. We only inflate a new View when the convertView supplied
            // by ListView is null.
            if (convertView == null) {
                convertView = mInflater.inflate(R.layout.list_item_icon_text, null);

                // Creates a ViewHolder and store references to the two children views
                // we want to bind data to.
                holder = new ViewHolder();
                holder.text = (TextView) convertView.findViewById(R.id.text);
                holder.icon = (ImageView) convertView.findViewById(R.id.icon);

                convertView.setTag(holder);
            } else {
                // Get the ViewHolder back to get fast access to the TextView
                // and the ImageView.
                holder = (ViewHolder) convertView.getTag();
            }

            // Bind the data efficiently with the holder.
            holder.text.setText(DATA[position]);
            holder.icon.setImageBitmap((position & 1) == 1 ? mIcon1 : mIcon2);

            return convertView;
        }

        static class ViewHolder {
            TextView text;
            ImageView icon;
        }
    }

后来他将viewHolder的定义改为final ViewHolder就解决了问题。

大概想了一下,因为android对ListView做了缓存优化,实际上内存里只保留了一屏幕的View,也就是参数里面的convertView,而之前viewHolder是在convertView为空的时候new出来的,并被convertView  setTag进去了,所以,后面取出来的ViewHold对象都是缓存的。但是对于每个holder里面的chatPic都要设定一个点击事件监听器。所以,其实只是对缓存的那些holder对象重复设置监听器。但是为什么将holder对象用final修饰就没问题了,由于final修饰的引用不会改变他所指向的对象。然后为什么这样就可以了我也想不清了,求看到的大神详解。

时间: 2024-11-02 06:29:42

ListView数据错位问题的相关文章

easyui使用datagrid时列名包含特殊字符导致表头与数据错位的问题

做一个用easyui的datagrid显示数据的功能时发现表格的列头与数据错位了,而且这个现象不总是能重现,一直没搞清楚原因.后来偶然在控制台看出了一点端倪: 推测表头或者单元格的class名应该是用字段名拼出来的,如果含有特殊字符可能违反了css的命名规则(权威的css命名规则暂时没有找到,这篇文章稍有提到). 我找了个有特殊字符的列的数据,发现果然歪了.验证了想法. 由于项目的特殊性,数据库的表是动态创建的,也就是部分列名是由用户输入的,比较随意(当然,列头是另外是有显示名称的). 所以这个

多线程更新已排序的Datagridview数据,造成数据错位

多线程更新已排序的Datagridview数据,触发Datagridview的auto-sort时间,数据重新排序,造成后面更新数据的更新错误. 解决方法: 方法一.设置Datagridview的表头属性,DataGridViewColumnSortMode 1. 如果已经有默认的排序表头DataGridView.SortedColumn, 则 : DataGridViewColumn column = dgv.SortedColumn; //默认的排序列 column.SortMode = D

viewpager动态加载listView数据

package com.example.viewpage; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import android.annotation.SuppressLint; import android.app.Activity; import android.graphics.BitmapFactory; import androi

50个Android开发技巧(24 处理ListView数据为空的情况)

在移动平台上为用户展示数据的一个经常用法是将数据填充进一个List内,而此时须要注意的一点就是: 原文地址:(http://blog.csdn.net/vector_yi/article/details/24936163) 怎样处理须要填充的数据为空的情况? ListView及其它继承自AdapterView的类都有一个简便的处理这样的情况的方法:setEmptyView(View). 当ListView的Adapter为空或者Adapter的isEmpty()方法返回true的时候,它将会把设

ListView数据动态刷新

在Android开发中用到ListView时,经常遇到要更改ListView内容的情形,比如删除或增加ListView中显示的条目,这里给大家提供一下思路:不论ListView要显示的对象是什么(如:Cursor或Array或List),要实现ListView数据的更新,都要手动去更改要显示的数据对象,然后调用相应的方法(如:requery()或notifyDataSetChanged())来刷新ListView.针对不同的情形,下面给出相应解决办法的关键代码: 1.用ListView来显示数据

从零开始学android<ListView数据列表显示组件.二十一.>

与滚动视图(ScrollView)类似的还有一种列表组件(ListView),可以将多个组件加入到ListView之中以达到组件的滚动显示效果,ListView组件本身也有对应的ListView类支持,可以通过操作ListView类以完成对此组组件的操作,ListView类的继承结构如下所示: java.lang.Object ? android.view.View ? android.view.ViewGroup ? android.widget.AdapterView<T extends a

Android零基础入门第44节:ListView数据动态更新

经过前面几期的学习,关于ListView的一些基本用法大概学的差不多了,但是你可能发现了,所有ListView里面要填充的数据都是静态的,但在实际开发中,这些数据往往都是动态变化的,比如数据内容发生改变.增加几行.或者删除几行,这就涉及到ListView数据的更新问题. 接下来通过一个简单的示例程序来学习ListView的数据更新. 继续使用WidgetSample工程,在app/main/res/layout/目录下创建updatedata_layout.xml文件,在其中填充如下代码片段:

listview数据下载后不更新

创建了适配器,listview也设置了适配器 数据更新后,也设置了通知适配器更新 而适配器也获得数据长度,说明数据是有到达适配器来更新 但是界面却没有显示数据 通过排查,问题出在listview的高度设置上 记录一下,避免类似问题.

ListView数据动态更新

经常会用到数据与前台控件绑定相关的问题,一直知道要用委托(代理)但每次都忘,而且每次都百度了一遍又一遍,就是不长记性,这次一定好好记下来下次就不会忘了. 后台数据与前台绑定主要分为两步: 第一步把要绑定的数据定义为一个数据集合或对象绑定到List中,方便调用: public class TestCase:INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged; private string