首页 > 代码库 > ListView数据错位问题

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修饰的引用不会改变他所指向的对象。然后为什么这样就可以了我也想不清了,求看到的大神详解。

ListView数据错位问题