前言

  在开发Android应用过程中经常要与列表展示打交道,比如Listview。在使用过程中如果不能正确的进行细节处理那么对性能还是有很大的损耗的。

  Listview展示内容是通过一个Adapter来进行内容绑定的。如下所示:

  

 class Adapter implements ListAdapter{

         @Override
public void registerDataSetObserver(DataSetObserver observer) { } @Override
public void unregisterDataSetObserver(DataSetObserver observer) { } @Override
public int getCount() {
return items.size();
} @Override
public Object getItem(int position) {
return items.get(position);
} @Override
public long getItemId(int position) {
return position;
} @Override
public boolean hasStableIds() {
return false;
} @Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder vh =null;
if(convertView==null){
vh = new ViewHolder();
convertView = mInflater.inflate(R.layout.item, null);
vh.tv = (TextView) convertView.findViewById(R.id.tvShow); convertView.setTag(vh);
}else{
vh = (ViewHolder) convertView.getTag();
} vh.tv.setText(items.get(position)); return convertView;
} @Override
public int getItemViewType(int position) {
return 1;
} @Override
public int getViewTypeCount() {
return 1;
} @Override
public boolean isEmpty() {
return false;
} @Override
public boolean areAllItemsEnabled() {
return false;
} @Override
public boolean isEnabled(int position) {
return true;
} }

  有了这个Adapter就可以与Listview进行数据绑定了,如下所示:

  

lv.setAdapter(new Adapter());

  

getViw

在Adapter类中有一个重要的实现方法getView用来实现大部分的逻辑,这个就是这篇文章的重点。

public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder vh =null;
if(convertView==null){
vh = new ViewHolder();
convertView = mInflater.inflate(R.layout.item, null);
vh.tv = (TextView) convertView.findViewById(R.id.tvShow); convertView.setTag(vh);
}else{
vh = (ViewHolder) convertView.getTag();
} vh.tv.setText(items.get(position)); return convertView;
}

  先看下这个方法的官方解释

  Get a View that displays the data at the specified position in the data set.
  You can either create a View manually or inflate it from an XML layout file.

  意思是说:获取一个用来展示数据集中指定位置的数据的视图。可以通过代码或者inflate一个XML文件来获得这个View对象。

  Parameters(参数)
      position

      The position of the item within the adapter's data set of the item whose view we want.

      我们要展示的数据集中的数据条目的位置
      convertView
          The old view to reuse, if possible. Note: You should check that this view is non-null and of an appropriate type before using.
          If it is not possible to convert this view to display the correct data, this method can create a new view.
     Heterogeneous lists can specify their number of view types, so that this View is always of the right type (see getViewTypeCount()and       getItemViewType(int)).

      一个能用就用的旧视图。注意:在使用之前你需要去检查这个视图是否非空以及其类型。

      如果这个视图不能用来正确展示数据,那么此方法就需要创建一个新的视图了。

      如果一个列表中有多种视图类型,那么也可以通过getViewTypeCount\getItemViewType方法来正确使用。
      parent     
          The parent that this view will eventually be attached to

      这个视图要被添加到的对象

convertView

  上一段提到了convertView的reuse(重利用)的内容,也就是说在创建一个新视图去返回给List 的时候需要先检查下旧的视图对象是否还可以利用,包括去检查是否为空以及类型是否正确等等。当然大部分情况下是可以利用的,因此通过这种方式就降低了每次去创建一个item 的view的性能开销了

  view能够重复利用了,那么view中的对象是不是也能够重利用呢,比如其中的展示文本。当然,这就是这篇文章的标题提到的ViewHolder。

ViewHolder

  从字面上理解ViewHolder,a holder of the view,就是一个视图的持有者,持有的内容就是视图的所有指定内容,或者说是绑定内容(下面会提到绑定)。个人理解这个持有的意思,就好比是一个引用或者一个指针,ViewHolder中的内容发生了变化那么对应的view中也会随之发生变化;view中的内容发生了变化那么ViewHolder中也随之发生了变化。这就是所谓的hold吧。下面就看下如果绑定一个ViewHolder。

  先要定义一个ViewHolder对象,对象里面的内容就是需要hold的视图的内容,比如List中每一个item就是一个TextView用来展示信息,那么如下所示:

static final class ViewHolder{
TextView tv;
}

  Item对象的XML,如下:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="20dip" > <TextView
android:layout_marginTop="5dip"
android:layout_marginBottom="5dip"
android:id="@+id/tvShow"
android:layout_width="wrap_content"
android:layout_height="wrap_content" /> </LinearLayout>

  ViewHolder中的tv就是用来hold  Item找那个的tvShow的。

  ViewHolder有了,那么下面就进入绑定过程。还是回过头来看下getView那个方法片段。

  

vh = new ViewHolder();
convertView = mInflater.inflate(R.layout.item, null);
vh.tv = (TextView) convertView.findViewById(R.id.tvShow); convertView.setTag(vh);

  先把ViewHolder和convertView两个对象建出来,然后通过vh.tv = (TextView) convertView.findViewById(R.id.tvShow);进行了绑定,这样他们之间就产生了关联。

  最后通过convertView.setTag(vh);方法使得View和ViewHolder产生了关联,也就是vh真正成为了convertView这个View的holder。

  通过这样的方式,以后如果重利用这个视图,就可以通过vh = (ViewHolder) convertView.getTag();的方法来吧这个Holder拿出来,修改其中的内容就可以通过下面的方式了vh.tv.setText(items.get(position));

  这样的话省去了findViwyById这样的查找,降低了开销

后记:

  Listview有很多中优化性能的方式,这个算是其中一种。

完整代码:ViewHolderDemo

原文连接:http://www.cnblogs.com/luoaz/p/3734999.html

  

Android:ListView之ViewHolder的更多相关文章

  1. 【腾讯Bugly干货分享】Android ListView与RecyclerView对比浅析--缓存机制

    本文来自于腾讯bugly开发者社区,非经作者同意,请勿转载,原文地址:http://dev.qq.com/topic/5811d3e3ab10c62013697408 作者:黄宁源 一,背景 Recy ...

  2. Android ListView 常用技巧

    Android ListView 常用技巧 Android TextView 常用技巧 1.使用ViewHolder提高效率 ViewHolder模式充分利用了ListView的视图缓存机制,避免了每 ...

  3. Android ListView添加多种类型的ItemView

    一般复杂的ListView都会重写BaseAdapter,通过重用convertView来减少inflate,通过setTag()和ViewHolder改变ItemView的内容. 重写BaseAda ...

  4. Android ListView滑动过程中图片显示重复错乱闪烁问题解决

    最新内容建议直接访问原文:Android ListView滑动过程中图片显示重复错乱闪烁问题解决 主要分析Android ListView滚动过程中图片显示重复.错乱.闪烁的原因及解决方法,顺带提及L ...

  5. Android ListView(Selector 背景图片 全选 Checkbox等按钮)

    list_item.xml <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xm ...

  6. Android listview 的优化

    接[Android listview的应用][1] 在我们上一篇[Android listview的应用][1]中,我们的adapter中的getView()方法中每次都将布局重新加载一遍,这样就会导 ...

  7. android listview需要呈现多个布局

    android listview需要呈现多个布局 之前的做法很笨 在getView()方法里面,不仅将viewHolder作为tag属性设置给convertView 还将当前的position作为ta ...

  8. android ListView优化

    android ListView通过优化重用历史缓存实现.listview相应的数据适配器一般使用自己定义BaseAdapter子类,重用历史缓冲区来提高性能. 例如,下面的示例代码演示: 1.lis ...

  9. [置顶] android ListView包含Checkbox滑动时状态改变

    题外话: 在xamarin android的开发中基本上所有人都会遇到这个小小的坎,的确有点麻烦,当时我也折腾了好一半天,如果你能看到这篇博客,说明你和我当初也是一样的焦灼,如果你想解决掉这个小小的坎 ...

随机推荐

  1. 高级I/O之readv和writev函数

    readv和writev函数用于在一次函数调用中读.写多个非连续缓冲区.有时也将这两个函数称为散布读(scatter read)和聚集写(gather write). #include <sys ...

  2. debian之source.list详解

    之前安装的是debian sarge(内核是2.4.7),不太想更新,但是发现原来的源/ect/apt/source.lists如下,但是用apt-get update,发现大都已经不可用了.怎么办, ...

  3. uint8_t / uint16_t / uint32_t /uint64_t 是什么数据类型(转)

    在nesc的代码中,你会看到很多你不认识的数据类型,比如uint8_t等.咋一看, 好像是个新的数据类型,不过C语言(nesc是C的扩展)里面好像没有这种数据类型啊!怎么又是u又是_t的?很多人有这样 ...

  4. HBase shell 常用指令

    HBase shell 常用指令 连接HBase $ ./bin/hbase shell 打开帮助 hbase(main):001:0> help 创建表 hbase(main):003:0&g ...

  5. Scala Error: error while loading Suite, Scala signature Suite has wrong version expected: 5.0 found: 4.1 in Suite.class

    准备给scala项目引入单元测试 <dependency> <groupId>org.scalatest</groupId> <artifactId>s ...

  6. 小白日记11:kali渗透测试之服务扫描-banner、dmitry、nmap特征库、操作系统识别、SNMP

    服务扫描 不能单纯的以端口辨别服务.很多网络服务是漏洞频发的高危对象,对网络上的特定服务进行扫描,往往能让我们少走弯路,增加渗透成功的几率.确定开放端口后,通常会对相应端口上所运行服务的信息进行更深入 ...

  7. proxy代理类

    package cn.hncu.proxy.rent; import java.lang.reflect.InvocationHandler;import java.lang.reflect.Meth ...

  8. Android(java)学习笔记80:UDP协议发送数据

    UDP协议发送数据:我们总是先运行接收端,再运行发送端发送端: 1 package cn.itcast_02; import java.io.IOException; import java.net. ...

  9. LAMP平台搭建详解

    准备工作 安装编译工具 # yum -y install gcc # yum -y install gcc-c++ 如果系统之前已经安装有rpm包的mysql和apache,那么可以: #servic ...

  10. 关于HashMap根据Value获取Key

    关于我对java中集合的总结有如下三篇: 关于JDK中的集合总结(一) 关于JDK中的集合总结(二) 关于JDK中的集合总结(三) 关于数组集合之间的转换 Map中是一个key有且只有一个value. ...