ViewHolder模式中setTag和getTag的工作原理是什么?

时间:2014-09-22 04:24:03

标签: android listview android-adapter android-viewholder

我有一个简单的代码段,用于实现自定义列表视图。

我的代码如下:

WeatherAdapter.java:

public class WeatherAdapter extends ArrayAdapter<weather>{

    Context mcontext; 
    int mlayoutResourceId;    
   weather mdata[] = null;
   View row;

    public WeatherAdapter(Context context, int layoutResourceId, weather[] data) {
        super(context, layoutResourceId, data);
        mlayoutResourceId = layoutResourceId;
       mcontext = context;
        mdata = data;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
      row = convertView;
        WeatherHolder holder = null;

        if(row == null)
        {
            LayoutInflater inflater = ( (Activity) mcontext).getLayoutInflater();
            row = inflater.inflate(mlayoutResourceId, parent, false);

            holder = new WeatherHolder(row);


            row.setTag(holder);

        }
        else
        {
            holder = (WeatherHolder)row.getTag();
        }

        weather w = mdata[position];
        holder.txtTitle.setText(w.mtitle);
        holder.imgIcon.setImageResource(w.micon);

        return row;
    }

WeatherHolder.java

class WeatherHolder
    {
        ImageView imgIcon;
        TextView txtTitle;


    public WeatherHolder(View v){

          imgIcon = (ImageView)row.findViewById(R.id.imgIcon);
          txtTitle = (TextView)row.findViewById(R.id.txtTitle);

    }
    }
}

我在SO和其他网站上看到了很多答案,我理解了listview的回收机制。

我也理解,从viewholder,我们可以在适配器中保存子视图,我们不必多次调用findViewById()。所以,它是为了优化。

但我只有setTag(holder)getTag()方法中的混淆。 From this question,我发现它是为多个对象创建一个键值对,以便我们可以轻松访问它们。但是,我不明白为什么在这里需要它们...因为,我们没有多个持有者对象......只有我们每次都必须更改持有者的变量。我们可以在此处进行编码而不使用setTaggetTag吗?

任何人都可以更好地解释setTaggetTag做什么&#34;这里&#34 ;?

3 个答案:

答案 0 :(得分:24)

tag是一种机制,可让您views记住某些内容,可能是object integerstring或您喜欢的任何内容。

所以,当您的ListView首次创建convertViewnull时。因此,您需要创建一个新的convertView,并将references objects的{​​{1}} row放入viewHolder。然后将viewHolder保存到convertView setTag )的内存中。 Android会将convertView移至poolrecyclepasses将其再次发送给您。但其pool可能没有足够的convertViews,因此它会再次传递convertView null。所以故事再次重复,直到pool的{​​{1}}被填满。之后android从其池中获取android并将其传递给您。你会发现它不是convertView所以你问我第一次给你的对象null在哪里? ( getTag )所以你会得到那些并做你喜欢的事。

在下面的详细说明

references

当你的but its pool may not have enough convertViews so it again passes a new convertView thats null要创建时,

android pool为空。因此,对于listView的第一项,它会向您发送必须显示的listView。之后convertView将其保存在android中,因此其pool现在只包含一个pool。对于你要创建android的convertView的第二项不能使用它的池,因为它实际上有一个元素,那个元素是你的第一个项目,它现在正在显示,所以它必须传递另一个{ {1}}。此过程会一直重复,直到listViewconvertView中找到android现在未显示的convertView并将其传递给您。

当你滚动使用持有者的列表时,Android会对每一行进行充气,直到屏幕填满为止。

答案 1 :(得分:16)

让我们从不同的角度看:

enter image description here

让我们想象 Helicopter 是&#34; &#34;而是&#34; setTag &#34;下面的汽车是&#34; WeatherHolder &#34;,但直升机的飞行员在那辆汽车内,他/她是管理控制直升机的人a&#34; WIRED REMOTE&#34;。

当你切断绳索时,#34; setTag&#34;直升机仍在飞行,但飞行员无法控制它,因为飞行员在地面下降,这意味着飞行员现在已经死了! (在java中,当一个对象丢失它的引用时,垃圾收集器将收集该内容并从内存中释放出来。)

当直升机即将飞行在飞行员所在的地方时,你没有将绳子放置或附着在汽车上 - 你可能会失去对直升机的控制,因为你正在使用&#34; WIRED REMOTE&#34;。

我希望这有帮助:)。

答案 2 :(得分:2)

  

但是,我不明白为什么在这里需要它们...因为,我们没有多个持有者对象

这是你错的地方 - 每个视图都有一个持有者(也就是可见或缓存的ListView条目)。