View 的 setTag() getTag() 方法的主要用途是什么?

发布于 2024-10-21 21:20:18 字数 126 浏览 1 评论 0原文

View类型对象的setTag()getTag()等方法的主要用途是什么?

我认为我可以将任意数量的对象与单个视图关联起来,这样的想法正确吗?

What is the main purpose of such methods as setTag() and getTag() of View type objects?

Am I right in thinking that I can associate any number of objects with a single View?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

谁把谁当真 2024-10-28 21:20:18

假设您生成了一堆相似的视图。您可以为每个视图单独设置一个 OnClickListener

button1.setOnClickListener(new OnClickListener ... );
button2.setOnClickListener(new OnClickListener ... );
 ...

然后您必须为每个视图创建一个唯一的 onClick 方法,即使它们执行类似的操作,例如:

public void onClick(View v) {
    doAction(1); // 1 for button1, 2 for button2, etc.
}

这是因为 < code>onClick 只有一个参数,即 View,并且它必须从封闭范围内的实例变量或最终局部变量获取其他信息。我们真正想要的是从视图本身获取信息。

输入 getTag/setTag

button1.setTag(1);
button2.setTag(2);

现在我们可以为每个按钮使用相同的 OnClickListener:

listener = new OnClickListener() {
    @Override
    public void onClick(View v) {
        doAction(v.getTag());
    }
};

这基本上是视图拥有记忆的一种方式。

Let's say you generate a bunch of views that are similar. You could set an OnClickListener for each view individually:

button1.setOnClickListener(new OnClickListener ... );
button2.setOnClickListener(new OnClickListener ... );
 ...

Then you have to create a unique onClick method for each view even if they do the similar things, like:

public void onClick(View v) {
    doAction(1); // 1 for button1, 2 for button2, etc.
}

This is because onClick has only one parameter, a View, and it has to get other information from instance variables or final local variables in enclosing scopes. What we really want is to get information from the views themselves.

Enter getTag/setTag:

button1.setTag(1);
button2.setTag(2);

Now we can use the same OnClickListener for every button:

listener = new OnClickListener() {
    @Override
    public void onClick(View v) {
        doAction(v.getTag());
    }
};

It's basically a way for views to have memories.

我想补充几句话。

尽管在 ViewHolder 模式的特定情况下使用 get/setTag(Object) 似乎非常有用,但我建议在其他情况下使用它之前要三思而后行。几乎总是有另一种具有更好设计的解决方案。

主要原因是这样的代码很快就会变得不支持。

  • 对于其他开发人员来说,您设计在视图中存储为标记的内容并不明显。 setTag/getTag 方法根本没有描述性。

  • 它只存储一个Object,当您想要getTag时需要对其进行强制转换。当您决定更改标记中存储对象的类型时,稍后可能会发生意外崩溃。

  • 这是一个真实的故事:我们有一个相当大的项目,有很多适配器、带有视图的异步操作等等。一位开发人员决定在他的代码部分中设置 set/getTag,但另一位开发人员已经将此标记设置到该视图。最后有人找不到自己的标签,很迷茫。我们花了几个小时才找到这个 bug。

setTag(int key, Object tag) 看起来好多了,因为您可以为每个标签生成唯一的键(使用 id 资源),但是对于 Android 有一个显着的限制 << 4.0。来自 Lint 文档:

Android 4.0之前,View.setTag(int, Object)的实现
将把对象存储在静态映射中,其中的值是
强烈引用。这意味着如果该对象包含任何
指向上下文的引用,上下文(指向
几乎所有其他东西)都会泄漏。如果你经过一个视图,这个视图
提供对创建它的上下文的引用。同样,查看
持有者通常包含一个视图,并且游标有时也包含
与视图相关联。

I'd like to add few words.

Although using get/setTag(Object) seems to be very useful in the particular case of a ViewHolder pattern, I'd recommend to think twice before using it in other cases. There is almost always another solution with better design.

The main reason is that code like that becomes unsupportable pretty quickly.

  • It is non-obvious for other developers what you designed to store as tag in the view. The methods setTag/getTag are not descriptive at all.

  • It just stores an Object, which requires to be cast when you want to getTag. You can get unexpected crashes later when you decide to change the type of stored object in the tag.

  • Here's a real-life story: We had a pretty big project with a lot of adapters, async operations with views and so on. One developer decided to set/getTag in his part of code, but another one had already set the tag to this view. In the end, someone couldn't find his own tag and was very confused. It cost us several hours to find the bug.

setTag(int key, Object tag) looks much better, cause you can generate unique keys for every tag (using id resources), but there is a significant restriction for Android < 4.0. From Lint docs:

Prior to Android 4.0, the implementation of View.setTag(int, Object)
would store the objects in a static map, where the values were
strongly referenced. This means that if the object contains any
references pointing back to the context, the context (which points to
pretty much everything else) will leak. If you pass a view, the view
provides a reference to the context that created it. Similarly, view
holders typically contain a view, and cursors are sometimes also
associated with views.

☆獨立☆ 2024-10-28 21:20:18

我们可以使用 setTag()getTag() 根据我们的要求设置和获取自定义对象。 setTag() 方法采用 Object 类型的参数,而 getTag() 返回一个 Object

例如,

Person p = new Person();
p.setName("Ramkailash");
p.setId(2000001);
button1.setTag(p);

We can use setTag() and getTag() to set and get custom objects as per our requirement. The setTag() method takes an argument of type Object, and getTag() returns an Object.

For example,

Person p = new Person();
p.setName("Ramkailash");
p.setId(2000001);
button1.setTag(p);
清醇 2024-10-28 21:20:18

对于 Web 开发人员来说,这似乎相当于数据......

For web developers, this seems to be the equivalent to data-..

·深蓝 2024-10-28 21:20:18

这对于自定义 ArrayAdapter 使用非常有用。这是某种优化。 setTag 用作对布局某些部分(在 ListView 中显示)的引用的对象的引用,而不是 findViewById

static class ViewHolder {
    TextView tvPost;
    TextView tvDate;
    ImageView thumb;
}

public View getView(int position, View convertView, ViewGroup parent) {

    if (convertView == null) {
        LayoutInflater inflater = myContext.getLayoutInflater();
        convertView = inflater.inflate(R.layout.postitem, null);

        ViewHolder vh = new ViewHolder();
        vh.tvPost = (TextView)convertView.findViewById(R.id.postTitleLabel);
        vh.tvDate = (TextView)convertView.findViewById(R.id.postDateLabel);
        vh.thumb = (ImageView)convertView.findViewById(R.id.postThumb);
        convertView.setTag(vh);
    }
            ....................
}

This is very useful for custom ArrayAdapter using. It is some kind of optimization. There setTag used as reference to object that references on some parts of layout (that displaying in ListView) instead of findViewById.

static class ViewHolder {
    TextView tvPost;
    TextView tvDate;
    ImageView thumb;
}

public View getView(int position, View convertView, ViewGroup parent) {

    if (convertView == null) {
        LayoutInflater inflater = myContext.getLayoutInflater();
        convertView = inflater.inflate(R.layout.postitem, null);

        ViewHolder vh = new ViewHolder();
        vh.tvPost = (TextView)convertView.findViewById(R.id.postTitleLabel);
        vh.tvDate = (TextView)convertView.findViewById(R.id.postDateLabel);
        vh.thumb = (ImageView)convertView.findViewById(R.id.postThumb);
        convertView.setTag(vh);
    }
            ....................
}
绳情 2024-10-28 21:20:18

与 ID 不同,标签不用于识别视图。标签本质上是可以与视图关联的额外信息。它们最常用于在视图本身中存储与视图相关的数据,而不是将它们放在单独的结构中。

参考: http://developer.android.com/reference/android/view/View .html

Unlike IDs, tags are not used to identify views. Tags are essentially an extra piece of information that can be associated with a view. They are most often used as a convenience to store data related to views in the views themselves rather than by putting them in a separate structure.

Reference: http://developer.android.com/reference/android/view/View.html

云淡月浅 2024-10-28 21:20:18

当您有 ListView 并想要回收/重用视图时,设置 TAG 非常有用。通过这种方式,ListView 变得与较新的 RecyclerView 非常相似。

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

if ( convertView == null )
{
    /* There is no view at this position, we create a new one. 
       In this case by inflating an xml layout */
    convertView = mInflater.inflate(R.layout.listview_item, null);  
    holder = new ViewHolder();
    holder.toggleOk = (ToggleButton) convertView.findViewById( R.id.togOk );
    convertView.setTag (holder);
}
else
{
    /* We recycle a View that already exists */
    holder = (ViewHolder) convertView.getTag ();
}

// Once we have a reference to the View we are returning, we set its values.

// Here is where you should set the ToggleButton value for this item!!!

holder.toggleOk.setChecked( mToggles.get( position ) );

return convertView;
}

Setting of TAGs is really useful when you have a ListView and want to recycle/reuse the views. In that way the ListView is becoming very similar to the newer RecyclerView.

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

if ( convertView == null )
{
    /* There is no view at this position, we create a new one. 
       In this case by inflating an xml layout */
    convertView = mInflater.inflate(R.layout.listview_item, null);  
    holder = new ViewHolder();
    holder.toggleOk = (ToggleButton) convertView.findViewById( R.id.togOk );
    convertView.setTag (holder);
}
else
{
    /* We recycle a View that already exists */
    holder = (ViewHolder) convertView.getTag ();
}

// Once we have a reference to the View we are returning, we set its values.

// Here is where you should set the ToggleButton value for this item!!!

holder.toggleOk.setChecked( mToggles.get( position ) );

return convertView;
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文