首页 > 技术文章 > 优化ListView时重用Item导致错位

gmm283029 2014-12-15 18:59 原文

常用的ListView的优化方式是使用getView方法的convertView参数和一个内部类ViewHolder配合来使用的

原理:如代码中,重用convertView意味着之后重新调用getView的时候if中的代码就不再执行了(getView方法是Adapter在绘制AbsList的时候每一个item都会调一次),那我们看看if中的代码是干什么的,初始化控件用的,findViewById在一大堆id中找控件的时候是需要消耗时间的,如果不重用,初始化多少控件就find多少次,自然就卡了,当然还有其他导致listview卡的原因。

顺便粘贴一下,会的可以无视。

public View getView(int arg0, View arg1, ViewGroup arg2) {

		ViewHolder mViewHolder=null;
		if (arg1 == null) {
			//View就是convertView参数,当它为空的时候创建一次,同时实例化一个ViewHolder对象			
			mViewHolder = new ViewHolder();
			arg1 = LayoutInflater.from(mContext).inflate(
					R.layout.fragment_market_firstpage_griditem2, null);
			mViewHolder.mTitle = (FontTextView) arg1
					.findViewById(R.id.group_item2_title);
			mViewHolder.mDescription = (FontTextView) arg1
					.findViewById(R.id.group_item2_summary);
			mViewHolder.mIcon = (NetworkImageView) arg1
					.findViewById(R.id.group_item2_icon);
			mViewHolder.mRatingBar = (RatingBar) arg1
					.findViewById(R.id.group_item2_ratingBar1);
			//使用完之后setTag一下,
			//View中的setTag(Onbect)表示给View添加一个格外的数据,以后可以用getTag()将这个数据取出来,如下在else中我们将它取出来重用了
			arg1.setTag(mViewHolder);
		} else {
			mViewHolder = (ViewHolder) arg1.getTag();
		}
		mViewHolder.mTitle.setText(mList.get(arg0).getTitle());
		mViewHolder.mDescription.setText(mList.get(arg0).getDescription());
		mViewHolder.mIcon.setImageUrl(mList.get(arg0).getIcon_link(),
				LauncherApplication.getInstance().getImageLoader());
		mViewHolder.mIcon.setDefaultImageResId(R.drawable.feature_default);
		mViewHolder.mIcon.setErrorImageResId(R.drawable.feature_default);
		mViewHolder.mRatingBar.setRating((float) mList.get(arg0).getRatings());
		if (arg0 > lastPosition) {
			Animation animation = AnimationUtils.loadAnimation(mContext,
					R.anim.listview_up_from_bottom);
			animation.setInterpolator(AnimationUtils.loadInterpolator(mContext,
					android.R.anim.accelerate_interpolator));
			arg1.startAnimation(animation);
			lastPosition = arg0;
		}
		return arg1;
	}
	//内部类来声明你的item中的控件
	class ViewHolder {
		FontTextView mTitle, mDescription;
		NetworkImageView mIcon;
		RatingBar mRatingBar;
	}

那么这样写有什么问题呢?

如果我们发生这种情况:如图是豌豆荚的广告SDK中的app列表墙,我只点击了“当当”之后我开始往下滚,发现第二页中也显示了一个app正在下载,等在下载完成后,提示我们安装的是"当当",第二的页的app其实并没有下载,我们只是重用了item之后导致的,也就是常说的视图错位。这种情况发生的机会还是很大的,只要你的list中区别于其他的item就肯定会发生。

   

解决方式:

继承Adapter的时候重写getItemViewType(int position)和getViewTypeCount()


getItemViewType(int position)中的中的positon参数表示你adapter的索引,也就是第几项。

这个方法返回一个int,表示你当前的这个item的类型。


getViewTypeCount()返回你的所有要显示的类型的种类数。就是总共有多少种类型的Item

如下:

<span style="font-size:14px;">@Override
		public int getItemViewType(int position) {//第一项和第二项属于一类,剩下的属于一类
			if (position == 0) {
				return 0;
			} else if (position == 1) {
				return 0;
			} else {
				return 1;
			}
		}

		@Override
		public int getViewTypeCount() {//表示我共有两种item要显示,
			// TODO Auto-generated method stub
			return 2;
		}</span>


在getView中d使用:直接判断getView的positon参数,用来区别item

if (position == 0 || position == 1) {
				
			}


或者在getView调用前面重写的getItemViewType(int positon),根据返回值区别,position传getVIew的position。

int type = getItemViewType(arg0);
switch(type){
case 0:
break;
case 1:
break;
default:
break;
}




 

推荐阅读