ListView中convertView和ViewHolder的复用机制工作原理

最近碰到的面试题中经常会碰到问"ListView的优化"问题。所以就拿自己之前写的微博客户端的程序做下优化。
自己查了些资料,看了别人写的博客,得出结论,ListView优化大致从以下几个角度:
1.复用已经生成的convertView;
2.添加viewHolder类;
3.缓存数据(图片缓存);
4.分页加载。

一、复用convertView
首先讲下ListView的原理:ListView中的每一个Item显示都需要Adapter调用一次getView的方法,这个方法会传入一个convertView的参数,返回的View就是这个Item显示的View。如果当Item的数量足够大,再为每一个Item都创建一个View对象,必将占用很多内存,创建View对象(mInflater.inflate(R.layout.lv_item, null);从xml中生成View,这是属于IO操作)也是耗时操作,所以必将影响性能。Android提供了一个叫做Recycler(反复循环器)的构件,就是当ListView的Item从上方滚出屏幕视角之外,对应Item的View会被缓存到Recycler中,相应的会从下方生成一个Item,而此时调用的getView中的convertView参数就是滚出屏幕的Item的View,所以说如果能重用这个convertView,就会大大改善性能。




图解:一个屏幕最多显示7个Item,如果当Item1滑出屏幕,此时Item1 的View被添加进Recycler中,相应的在下部要产生一个Item8,这时调用getView方法,convertView参数就是Item1 的View。


我们都知道在getView方法中的操作是这样的:先从xml中创建view对象(inflate操作,我们采用了重用convertView方法优化),然后在这个view去findViewById,找到每一个子View,如:一个TextView等。这里的findViewById操作是一个树查找过程,也是一个耗时的操作,所以这里也需要优化,就是使用viewHolder,把每一个子View都放在Holder中,当第一次创建convertView对象时,把这些子view找出来。然后用convertView的setTag将viewHolder设置到Tag中,以便系统第二次绘制ListView时从Tag中取出。当第二次重用convertView时,只需从convertView中getTag取出来就可以。

测试Demo:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public  View getView( int  position, View convertView, ViewGroup parent) {
          System.out.println( "getView "  + position +  " "  + convertView);
          ViewHolder holder =  null ;
          if  (convertView ==  null ) {
              convertView = mInflater.inflate(R.layout.lv_item,  null );
              holder =  new  ViewHolder();
              holder.textView = (TextView)convertView.findViewById(R.id.tv_text);
              convertView.setTag(holder);
          else  {
              holder = (ViewHolder)convertView.getTag();
          }
          holder.textView.setText(mData.get(position));
          return  convertView;
      }
}
 
  public  static  class  ViewHolder {
      public  TextView textView;
  }





  • 4
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
在 Android 开发 ListView 或 RecyclerView 时,为了提高列表的滑动流畅度和性能表现,通常会采用 ViewHolder 模式。ViewHolder 是一个用于保存 convertView View 的对象,可以通过 view.setTag() 方法将其与 convertView 绑定起来。在 getView() 或 onCreateViewHolder() 方法,如果 convertView 不为 null,则可以直接使用 convertView,并调用 getTag() 方法获取 ViewHolder 对象,避免频繁地调用 findViewById() 方法。这样可以大大减少 UI 线程的工作量,提高应用的性能表现。 具体实现步骤如下: 1. 在 Adapter 定义 ViewHolder 类,用于保存 convertView View 的对象。 ```java class ViewHolder { TextView title; ImageView icon; } ``` 2. 在 getView() 或 onCreateViewHolder() 方法,通过 convertViewViewHolder 实现优化。 ```java @Override public View getView(int position, View convertView, ViewGroup parent) { ViewHolder viewHolder; if (convertView == null) { convertView = LayoutInflater.from(context).inflate(R.layout.item_layout, parent, false); viewHolder = new ViewHolder(); viewHolder.title = convertView.findViewById(R.id.title); viewHolder.icon = convertView.findViewById(R.id.icon); convertView.setTag(viewHolder); } else { viewHolder = (ViewHolder) convertView.getTag(); } // 设置子 View 的数据 viewHolder.title.setText(getItem(position).getTitle()); viewHolder.icon.setImageResource(getItem(position).getIconResId()); return convertView; } ``` 在上述代码,如果 convertView 不为 null,则通过 convertView.getTag() 方法获取 ViewHolder 对象,否则创建新的 convertViewViewHolder 对象,并将其绑定起来,最后设置子 View 的数据并返回 convertView。 这样,就可以通过 ViewHolder 模式优化列表的性能表现。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值