理解用setTag 和 Viewholder 来优化listView

在说 setTag和getTag之前,我们先说下 Viewholder,它不是Android开发固定的API,而是谷歌Demo中推荐的设计方法。Viewholder对象它一般包括listview子项里所有的组件,convertView是空的,在Viewholder里存储对列表子项每个组件的id应用,通过setTag方法,把这个带有view引用的对象附加在View上,如此,当listView更新的时候,就不用再次去重复寻找引用,并且强制转换等工作,findViewById(R.id.img);通过getTag直接从view携带的Viewholder中取出每个组件的引用。

那么 setTag和
getTag的作用就很明显了,tag是标签的意思,但是在这里它不单单是作为view的标签,从本质上说,它是附加在view上面的任意数据,setTag(Object
obj) 形参是obj,任意对象。而getTag则更好理解了,既然setTag把数据附加上去,自然得有方法把它取下来再次使用。

请看代码——

用setTag和
getTag ,ViewHolder的代码

     ViewHolder holder;            if (convertView == null) {
                convertView = mInflater.inflate(R.layout.list_item_icon_text,
                        null);
                holder = new ViewHolder();
                holder.icon1 = (ImageView) convertView.findViewById(R.id.icon1);
                holder.text1 = (TextView) convertView.findViewById(R.id.text1);
                holder.icon2 = (ImageView) convertView.findViewById(R.id.icon2);
                holder.text2 = (TextView) convertView.findViewById(R.id.text2);
                convertView.setTag(holder);
            }
            else{
                holder = (ViewHolder)convertView.getTag();
            }
            holder.icon1.setImageResource(R.drawable.icon);
            holder.text1.setText(mData[position]);
            holder.icon2 .setImageResource(R.drawable.icon);
            holder.text2.setText(mData[position]);
}
 static class ViewHolder {
        TextView text1;
        ImageView icon1;
        TextView text2;
        ImageView icon2;
    }

没用setTag,getTag
和 ViewHolder的时候

 if (convertView == null) {
                convertView = mInflater.inflate(R.layout.list_item_icon_text,
                        null);
            }
            ((ImageView) convertView.findViewById(R.id.icon1)).setImageResource(R.drawable.icon);
            ((TextView) convertView.findViewById(R.id.text1)).setText(mData[position]);
            ((ImageView) convertView.findViewById(R.id.icon2)).setImageResource(R.drawable.icon);
            ((TextView) convertView.findViewById(R.id.text2)).setText(mData[position]);
}

当Android第一次加载第一页listView的时候,convertView是空的,因此通过

mInflater.inflate(R.layout.list_item_icon_text,

null);

这行代码实例化了一个 view给 convertView,然后加载数据,每一个组件(这里的是ImageView和TextView)都需要通过
findViewById这个方法去寻找视图控件。加载第一页的时候做一次这样的工作尚可忍受,然而,当加载第二页的时候, findViewById这个方法依然被调用,依次以后每次加载都如此。须知道,从xml中去寻找控件引用并加载时一件比较耗内存的事情,你每次都做这件事情,后果更甚。

因此,我定义了一个静态的 Viewholder类,放在静态存储区,并把组件引用通过setTag方法附加在View上面,当加载第二页的时候,你就不用再次去findViewById了,直接用getTag方法来取出数据引用即可。

这种方法叫做视图缓存。这也是2009年谷歌IO大会给出的优化建议。

如果你对这种方法存疑,有网友已经就这两种做法,还有另外一种,分别进行了数据测试,实测证明了,这个视图缓存方法的确是达到了优化的效果的。详情看此文章。

[Android]ListView性能优化之视图缓存

视图缓存的缺点——

应该注意到,这是一种以空间换时间的做法,因为增加了一个静态类,来达到减少 findViewById的次数。此外,setTag这样附加数据到view中会让view增加额外的负担,这样就造成了设置tag的view和不设置tag的view大小是不一样,只不过,我们一直都习惯了别人告诉我们这么做,没去比较而已。

网友农民伯伯通过反编译新浪微博而得到另外一种做法,就是用自定义的类(继承自RelativeLayout或其他容器),然后在这个里面直接把子元素findViewById后放到成员变量再暴露出来。

做法代码如下——
出自农民伯伯博客

 public View getView(int position, View convertView, ViewGroup parent) {
            // 开始计时
            long startTime = System.nanoTime();

            TestItemLayout item;
            if (convertView == null) {
                item = new TestItemLayout(BaseAdapterActivity.this);
            } else
                item = (TestItemLayout) convertView;
            item.icon1.setImageResource(R.drawable.icon);
            item.text1.setText(mData[position]);
            item.icon2.setImageResource(R.drawable.icon);
            item.text2.setText(mData[position]);

            // 停止计时
            long endTime = System.nanoTime();
            // 计算耗时
            long val = (endTime - startTime) / 1000L;
            Log.e("Test", "Position:" + position + ":" + val);
            if (count < 100) {
                if (val < 2000L) {
                    sum += val;
                    count++;
                }
            } else
                mTV.setText(String.valueOf(sum / 100L) + ":" + nullcount);// 显示统计结果
            return item;
        }
 
TestItemLayout
public class TestItemLayout extends LinearLayout {

    public TextView text1;
    public ImageView icon1;
    public TextView text2;
    public ImageView icon2;

    public TestItemLayout(Context context) {
        super(context);
        ((LayoutInflater) context
                .getSystemService(Context.LAYOUT_INFLATER_SERVICE)).inflate(
                R.layout.list_item_icon_text, this);
        icon1 = (ImageView) findViewById(R.id.icon1);
        text1 = (TextView) findViewById(R.id.text1);
        icon2 = (ImageView) findViewById(R.id.icon2);
        text2 = (TextView) findViewById(R.id.text2);
    }
}

个人理解:这种做法是不是用了反射的思想呢?当加载第二页的时候,  item = (TestItemLayout) convertView; 
把convertView强制类型转换成
自定义的布局容器,其中就能把每个组件的引用给转换出来?
求解释。

农民伯伯最后的验证结果是跟
使用视图缓存效果差不多,但是空间上优化了,并且由于没有使用Tag,view也不会变小了。

理解用setTag 和 Viewholder 来优化listView,布布扣,bubuko.com

时间: 2024-10-06 07:40:21

理解用setTag 和 Viewholder 来优化listView的相关文章

Android - ViewHolder优化ListView

在Android开发中, ListView是重要的组件, 它以列表形式根据数据的长度, 自适应展示具体内容. 用户可以自由的定义ListView每一列的布局. 当listview有大量数据需要加载的时候, 会占据内存, 影响性能. 这时候就需要按需填充, 并重新使用View, 减少对象的创建. ListView加载数据都是在getView()方法中进行. 同时, 需要自定义ListView重写ListAdapter: 如BaseAdapter, SimpleAdapter, CursorAdap

listView 利用viewholder进行优化

ListView优化:通过convertView+ViewHolder来实现,ViewHolder就是一个静态类,使用 ViewHolder 的关键好处是缓存了显示数据的视图(View),加快了 UI 的响应速度. 当我们判断 convertView == null  的时候,如果为空,就会根据设计好的List的Item布局(XML),来为convertView赋值,并生成一个viewHolder来绑定converView里面的各个View控件(XML布局里面的那些控件).再用convertVi

Android性能优化--Listview优化

ListView的工作原理 首先来了解一下ListView的工作原理(可参见http://mobile.51cto.com/abased-410889.htm),如图: ListView 针对每个item,要求 adapter “返回一个视图” (getView),也就是说ListView在开始绘制的时候,系统首先调用getCount()函数,根据他的返回值得到ListView的长度,然后根据这个长度,调用getView()一行一行的绘制ListView的每一项.如果你的getCount()返回

android-----带你一步一步优化ListView(二)

上一篇介绍了通常我们优化ListView的方式,但是这点对于要加载大量图片的ListView来说显然是不够的,因为我们知道要想获取一张图片不管是本地的还是网络的,其性能上均没有从内存中获取快,所以为了提升用户的体验度,对于加载图片的ListView,通常我们会通过缓存做以下优化: 基本思想: (1)如果想要加载图片,首先先去内存缓存中查看是否有图片(内存缓存) (2)如果内存缓存中没有,就会去本地SD卡上查找是否存在(SD卡缓存) (3)如果本地SD卡上也没有的话,则会去网络下载了,下载完成之后

Ace教你一步一步做Android新闻客户端(五) 优化Listview

今天写存货了 调试一些动画参数花了些时间 ,嘿嘿存货不多了就没法做教程了,今天来教大家优化listview,等下我把代码编辑下 这次代码有些多 所以我把条理给大家理清楚.思路就是把加载图片的权利交给OnScrollListener . 1 首先来到 NewsAdapter这个类 ,我们给他实现了一个 AbsListView.OnScrollListener 这个接口,这个接口有两个方法: @Override public void onScrollStateChanged(AbsListView

android-----带你一步一步优化ListView(一)

ListView作为android中最常使用的控件,可以以条目的形式显示大量的数据,经常被用于显示最近联系人列表,对于每一个 Item,均要求adapter的getView方法返回一个View,因此ListView的实现是离不开Adapter的,如果以MVC的思想来看ListView的话,ListView的显示相当于V,Adapter部分相当于C,而数据部分就相当于M了,接下来的几篇博客计划对ListView自己所了解的一些优化措施总结一下,希望能够帮助到大家: 先来看看如果我们不使用任何优化措

android-----带你一步一步优化ListView(三)

前两篇我们介绍了一般的优化ListView方法以及DiskLruCache优化ListView,见android-----带你一步一步优化ListView(一)和android-----带你一步一步优化ListView(二),这一篇我们将从内存缓存的角度来完成ListView的优化,使用的是LruCache,它的主要算法原理是把最近使用的对象用强引用存储在 LinkedHashMap 中,并且把最近最少使用的对象在缓存值达到预设定值之前从内存中移除,并没有一个固定的缓存大小是符合所有应用程序的,

android问题及其解决-优化listView卡顿和怎样禁用ListView的fling

问题解决-优化listView卡顿和怎样禁用ListView的fling 前戏非常长,转载请保留出处:http://blog.csdn.net/u012123160/article/details/47720257 问题产生 这算是刚到实习公司接触到的第一个任务.公司某一产品中某个界面的listView高速滑动会有卡顿的现象发生,我的任务就是解决它. 产生原因分析 我一開始的想法比較简单.可能是listview的优化没有做到位,比如convertView的复用.viewHolder的使用等等基础

常用的优化ListView效率的方法及其原理

在Android开发中,ListView的使用频率及其高,可以说99%的应用中你都可以看到他的身影. 在日常的开发工作中,我们一般会通过以下方法来优化ListView的效率: 1.复用getView方法中的convertView 一个ListView可能有很多Item,但是限于手机屏幕非常有限,所以只能显示很少的一部分Item,比如能显示10个,那么Android会在ListView中保存多余10个的Item, 溢出屏幕的Item会被回收到一个池子中,以备后用,那么就不用从新new出View对象