美文网首页
RecyclerView实现吸顶效果项目实战(二):ViewHo

RecyclerView实现吸顶效果项目实战(二):ViewHo

作者: bug音音 | 来源:发表于2020-12-29 22:26 被阅读0次

    ViewHolder 复用机制

    在使用 ListView 过程中适配器 Adapter 中的 getView() 方法中已经通过 convertView 复用机制(RecycleBin 回收再利用) 进行了优化。

    image

    但我们发现代码中仍然存在可以改进的地方,观察如下代码

    public View getView(int position, View convertView, ViewGroup parent) {  
        Fruit fruit = getItem(position);  
        View view;  
        if (convertView == null) {  
            view = LayoutInflater.from(getContext()).inflate(resourceId, null);  
        } else {  
            view = convertView;  
        }  
        ImageView fruitImage = (ImageView) view.findViewById(R.id.fruit_image);  
        TextView fruitName = (TextView) view.findViewById(R.id.fruit_name);  
        fruitImage.setImageResource(fruit.getImageId());  
        fruitName.setText(fruit.getName());  
        return view;  
    } 
    
    

    我们发现虽然 convertView 是实现了复用,但是每次 getView() 时,都要对每个子 View 中包含的控件进行实例化(findViewById)操作,这也是一个耗时的操作,这里就使用到了 ViewHolder 这个类来进行优化操作。

        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;
     }
    
    

    如上代码所述,我们把每个子 View 中包含的控件(需要实例化的)都放到 ViewHolder 的静态内部类中。当第一次创建 convertView 对象时,把 ViewHolder 中的控件都进行实例化,然后用 convertView 的 setTag() 方法将 ViewHolder 设置到 Tag 中,以便系统第二次调用 getView() 方法时子 View 中需要的控件可以直接通过 convertView.getTag() 方法取出 ViewHolder 容器对象,然后直接调用需要的控件即可。

    ListView 中的 convertView 和 ViewHolder 协同
    ListView 里面的每一个 item 都是通过 adapter 来得到的,然后根据 listView 的高度和 item 的高度来循环加载显示在 listView 上,因此首次加载就决定了能够显示出来的 item 的个数,并且首次走进的都是 getView() 方法里 convertView==null 的时候,也就是说,此时加载了几个 item(包括只显示一部分的),就创建了几个 ViewHolder 对象,ViewHolder 里的控件来指向对应的 convertView 里的控件。

    image

    图中显示了 ListView 显示出的6个 item,和对应生成的6个 ViewHolder 对象。并且在 ListView 工作过程中一直指向它们各自的 item。注意此时,RecycleBin 里还么有任何可以拿来复用的 convertView。若此时,ListView 向上滑动一部分,使得 item 1 一部分滚出 ListView 的 顶部,并且 item 7 也进入一部分,因为此时 RecycleBin 里没有任何可以复用的 convertView(废弃缓存里没有 View),所以,程序急促进入 convertView == null,ViewHolder 7也被创建,指向 item 7。如果此时继续滑动 item 1,使得页面刚好显示的是 item2-7, 将不会再生成新的 ViewHolder。此时滚出去的 item 1对应的 View 将被放入 RecycleBin 里面做备用的 convertView 1,如果继续往上滑动,item 8即将进入 ListView,此时 ListView 的 adapter 在 RecycleBin 里找到了可以复用的 convertView 1,而且因为之前用了 setTag 的方式,因此可以用 getTag 迅速获得 ViewHolder 1,并且 ViewHolder 1是始终指向 convertView 1,因此直接可以根据 position 来设置对应的图片,文本然后 return 此更新后的 View 给 ListView 来显示 item 8。

    做 ViewHolder 来优化 ListView 时,需要用 static 来修饰 ViewHolder 类?

    我们把 ViewHolder 类设置成 static 静态类,是想让整个内存中之需要一份 ViewHolder 对象,来优化 ListView。

    但是通过实验发现

        //把ViewHolder变为static之后,getView()里加上如下代码:
    viewHolder = new ViewHolder();
    AppLog.i("viewHolder" + i +" = " + viewHolder );
    i++;
    
    20.548 12491-12491/?  [getView()] - viewHolder1 = $ViewHolder@e6a668d
    20.627 12491-12491/?  [getView()] - viewHolder2 = $ViewHolder@22e2da45
    20.629 12491-12491/?  [getView()] - viewHolder3 = $ViewHolder@355bd5c1
    20.632 12491-12491/?  [getView()] - viewHolder4 = $ViewHolder@210f0cfd
    20.635 12491-12491/?  [getView()] - viewHolder5 = $ViewHolder@3c47bf9
    20.637 12491-12491/?  [getView()] - viewHolder6 = $ViewHolder@35c7deb5
    20.640 12491-12491/?  [getView()] - viewHolder7 = $ViewHolder@e64b131
    20.642 12491-12491/?  [getView()] - viewHolder8 = $ViewHolder@34222f6d
    20.644 12491-12491/?  [getView()] - viewHolder9 = $ViewHolder@34bf5569
    20.647 12491-12491/?  [getView()] - viewHolder10 = $ViewHolder@20eedf25
    20.650 12491-12491/?  [getView()] - viewHolder11 = $ViewHolder@27d348a1
    20.653 12491-12491/?  [getView()] - viewHolder12 = $ViewHolder@2e3acddd
    20.656 12491-12491/?  [getView()] - viewHolder13 = $ViewHolder@3290cc9e
    40.937 12491-12491/: [MainActivity$1:48 onScrollStateChanged()] - scroll
    44.879 12491-12491/: [MainActivity$1:52 onScrollStateChanged()] - fling
    44.994 12491-12491/: [MainActivity$1:44 onScrollStateChanged()] - idle
    
    

    静态内部类的实例地址都是不一样的,所以并没有优化 ViewHolder 的个数。然而实际情况是因为 convertView 的复用机制,convertView 不会太多,一般情况下=ListView 显示的 item 个数 + 1*viewTypeCount。所以 ViewHolder 的个数也不会太多。所以没有优化的意义。

    相关文章

      网友评论

          本文标题:RecyclerView实现吸顶效果项目实战(二):ViewHo

          本文链接:https://www.haomeiwen.com/subject/ipjkoktx.html