gpt4 book ai didi

android - ViewHolder - 良好实践

转载 作者:塔克拉玛干 更新时间:2023-11-02 07:53:36 25 4
gpt4 key购买 nike

一个小菜鸟问题。为什么要在getView()中初始化ViewHolder?为什么我们不能在构造函数中初始化它?

最佳答案

您将拥有多个 ViewHolder 对象。

ListView 本质上不会为其每一行创建新的 View 实例。这样一来,如果您有一个包含一百万个事物的 ListView,则无需为一百万个事物存储布局信息。那么你需要存储什么?只是屏幕上的东西。然后您可以一遍又一遍地重用这些 View 。这样,一百万个对象的 ListView 可能只有 10 个 subview 。

在您的自定义数组适配器中,您将有一个名为 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,那可能还不错,如果你有一个复杂的布局,或者你有多个要为其设置数据的 View ,你可能会损失一点一次又一次地寻找您的观点。

那么我们如何解决这个问题呢?好吧,在我们查找之后将 TextView 存储在某个地方是有意义的。所以我们引入了一个名为 ViewHolder 的类,它“持有” View 。所以在适配器内部,像这样引入一个内部类:

private static class ViewHolder {
TextView textView;
}

这个类是私有(private)的,因为它只是适配器的缓存机制,而且它是静态的,因此我们不需要引用适配器来使用它。

这将存储我们的 View ,这样我们就不必多次调用 row.findViewById。我们应该在哪里设置它?当我们第一次膨胀 View 时。我们在哪里存储它? View 有一个自定义的“标签”字段,可用于存储有关 View 的元信息——这正是我们想要的!然后,如果我们已经看到这个 View ,我们只需要查找标签而不是查找行中的每个 View ..

因此 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, parent, 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 的文本值,因为它已经是对回收 View 的引用!所以我们最终的适配器代码变成了:

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.
ViewHolder holder = null;
if(row == null) {
LayoutInflater inflater = (LayoutInflater)getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
row = inflater.inflate(R.layout.list_item, parent, 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, I'm just using a string, 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;
}

我们完成了!

一些需要考虑的事情:

  1. 如果您想更改一行中的多个 View ,这会发生什么变化?作为挑战,制作一个 ListView,其中每一行都有两个 TextView 对象和一个 ImageView
  2. 调试 ListView 时,检查几项以便您真正了解发生了什么:
    1. ViewHolder 的构造函数被调用了多少次。
    2. holder.textView.getText() 的值是什么,然后在 getView() 结束时更新它

关于android - ViewHolder - 良好实践,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13164054/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com