android – ViewHolder – 良好的做​​法

前端之家收集整理的这篇文章主要介绍了android – ViewHolder – 良好的做​​法前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
一个小新问题.为什么要在getView()中初始化ViewHolder?为什么我们不能在构造函数中初始化它?

解决方法

您将有多个ViewHolder对象存在.

ListView的性质不会为每个行创建新的View实例.这样,如果你有一个ListView的一百万的东西,你不需要存储布局信息一百万的东西.那么你需要储存什么?只是屏幕上的东西.然后,您可以重复使用这些视图.这样一来,你的ListView的百万个对象就可以有10个子视图.

在您的自定义阵列适配器中,您将有一个名为getView()的函数,如下所示:

public View getView(int position,View convertView,ViewGroup parent) {
    //Here,position is the index in the list,the convertView is the view to be
    //recycled (or created),and parent is the ListView itself.

    //Grab the convertView as our row of the ListView
    View row = convertView;

    //If the row is null,it means that we aren't recycling anything - so we have
    //to inflate the layout ourselves.
    if(row == null) {
          LayoutInflater inflater = (LayoutInflater)getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
          row = inflater.inflate(R.layout.list_item,parent,false);
    }

    //Now either row is the recycled view,or one that we've inflated. All that's left
    //to do is set the data of the row. In this case,assume that the row is just a
    //simple TextView
    TextView textView = (TextView) row.findViewById(R.id.listItemTextView);

    //Grab the item to be rendered. In this case,I'm just using a string,but
    //you will use your underlying object type.
    final String item = getItem(position);

    textView.setText(item);

    //and return the row
    return row;
}

这将会奏效,但请花一点时间看看您是否能够发现这里的效率低下.想想上面的代码中的哪一个将被称为冗余.

问题是我们一遍又一遍地调用row.findViewById,即使在第一次查找之后,它也永远不会改变.而如果你的列表中只有一个简单的TextView,那可能并不是那么糟糕,如果你有一个复杂的布局,或者你有多个视图来设置数据,你可能会失去一点时间找到你的视图,再次.

那么我们如何解决这个问题呢?那么在我们查找之后,将TextView存储在某个地方是有意义的.所以我们介绍一个名为ViewHolder的类,它将“保存”视图.所以在适配器的内部,介绍一个内部类,如:

private static class ViewHolder {
    TextView textView;
}

这个类是私有的,因为它只是适配器的缓存机制,它是静态的,所以我们不需要引用适配器来使用它.

这将存储我们的视图,以便我们不必多次调用row.findViewById.我们应该在哪里设置?当我们第一次夸张的观点.我们在哪里存储?视图具有自定义标签”字段,可用于存储关于视图的元信息 – 正是我们想要的!那么,如果我们已经看到了这个视图,我们只需要查找标签,而不是查看行中的每个视图.

所以getView()中的if语句变成:

//If the row is null,it means that we aren't recycling anything - so we have
//to inflate the layout ourselves.
ViewHolder holder = null;
if(row == null) {
    LayoutInflater inflater = (LayoutInflater)getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    row = inflater.inflate(R.layout.list_item,false);
    //Now create the ViewHolder
    holder = new ViewHolder();
    //and set its textView field to the proper value
    holder.textView =  (TextView) row.findViewById(R.id.listItemTextView);
    //and store it as the 'tag' of our view
    row.setTag(holder);
} else {
    //We've already seen this one before!
    holder = (ViewHolder) row.getTag();
}

现在,我们只需要更新holder.textView的文本值,因为它已经是对循环视图的引用!所以我们的最终适配器的代码变成:

public View getView(int position,it means that we aren't recycling anything - so we have
    //to inflate the layout ourselves.
    ViewHolder holder = null;
    if(row == null) {
        LayoutInflater inflater = (LayoutInflater)getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        row = inflater.inflate(R.layout.list_item,false);
        //Now create the ViewHolder
        holder = new ViewHolder();
        //and set its textView field to the proper value
        holder.textView =  (TextView) row.findViewById(R.id.listItemTextView);
        //and store it as the 'tag' of our view
        row.setTag(holder);
    } else {
        //We've already seen this one before!
        holder = (ViewHolder) row.getTag();
    }

    //Grab the item to be rendered. In this case,but
    //you will use your underlying object type.
    final String item = getItem(position);

    //And update the ViewHolder for this View's text to the correct text.
    holder.textView.setText(item);

    //and return the row
    return row;
}

我们完成了

有些事情要考虑:

>如果您想要更改一行中的多个视图,该怎么改?作为一个挑战,做一个ListView,每一行都有两个TextView对象和一个ImageView
>调试您的ListView时,请检查一些事情,以便您可以真正了解发生的情况:

> ViewHolder的构造函数调用多少次.>在getView()结尾更新之前,holder.textView.getText()的值是多少?

猜你在找的Android相关文章