Какова основная цель setTag () getTag () методов View?

421

Какова главная цель таких методов , как setTag()и getTag()из Viewобъектов типа?

Правильно ли я считаю, что могу связать любое количество объектов с одним представлением?

Евгений
источник

Ответы:

636

Допустим, вы генерируете кучу просмотров, которые похожи. Вы можете установить OnClickListenerдля каждого представления индивидуально:

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

Затем вы должны создать уникальный onClickметод для каждого представления, даже если они делают схожие вещи, например:

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

Это связано с тем, что он onClickимеет только один параметр a Viewи должен получать другую информацию из переменных экземпляра или конечных локальных переменных во вложенных областях. Что мы действительно хотим, так это получить информацию от самих мнений .

Введите getTag/ setTag:

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

Теперь мы можем использовать один и тот же OnClickListener для каждой кнопки:

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

Это в основном способ для представлений иметь воспоминания .

Мэтью Уиллис
источник
8
@ Мэтью Уиллис, но мы можем сделать это и с помощью view.getId (). не так ли ?
Android Killer
50
@AndroidKiller вы могли бы, но с помощью setTag () вы можете поместить любой объект, который вы хотите, даже пользовательские классы - так что вы можете использовать их для сохранения ссылки на данные, которые отображает представление
Даниэль
Что мне делать, если я хочу изменить только цвет фона кнопки, на которую нажали ??? Я получаю позицию с помощью getTag ().
Сагар Деванга
2
@Sagar: public void ui_click(View view){ if(20==((int)view.getTag())) view.setBackgroundColor(colorInt); }должен сделать трюк для цветной части. 20 - это просто заполнитель для проверяющей позиции вашего просмотра.
РиА
Я думаю, что это старый способ. новый способ заключается в использовании общих аргументов, обеспечивающих безопасность типов. но это все же хорошо.
М.Казем Ахгари
124

Я хотел бы добавить несколько слов.

Хотя использование, get/setTag(Object)кажется, очень полезно в конкретном случае шаблона ViewHolder, я рекомендую дважды подумать, прежде чем использовать его в других случаях. Почти всегда есть другое решение с лучшим дизайном.

Основная причина в том, что подобный код довольно быстро перестает работать.

  • Для других разработчиков не очевидно, что вы разработали для хранения в качестве тега в представлении. Методы setTag/getTagне являются описательными вообще.

  • Он просто хранит объект Object, который требуется разыграть, когда вы этого хотите getTag. Вы можете получить неожиданные сбои позже, когда решите изменить тип хранимого объекта в теге.

  • Вот реальная история: у нас был довольно большой проект с множеством адаптеров, асинхронными операциями с представлениями и так далее. Один разработчик решил set/getTagв своей части кода, но другой уже установил тег для этого представления. В конце концов, кто-то не смог найти свой собственный тег и был очень смущен. Чтобы найти ошибку, нам понадобилось несколько часов.

setTag(int key, Object tag)выглядит намного лучше, потому что вы можете генерировать уникальные ключи для каждого тега (используя ресурсы id ), но есть существенное ограничение для Android <4.0. Из документов Lint:

До Android 4.0 реализация View.setTag (int, Object) сохраняла объекты в статической карте, где на значения были жесткие ссылки. Это означает, что если объект содержит какие-либо ссылки, указывающие на контекст, контекст (который указывает практически на все остальное) будет утечкой. Если вы передаете представление, оно предоставляет ссылку на контекст, который его создал. Точно так же, держатели вида обычно содержат вид, и курсоры иногда также связаны с представлениями.

Андрей Буней
источник
2
Спасибо, очень полезно! ... Вы случайно не знаете, что то, что находится в теге, восстанавливается между действиями?
Гунар
25

Мы можем использовать setTag()и getTag()для установки и получения пользовательских объектов в соответствии с нашим требованием. setTag()Метод принимает аргумент типа Object, и getTag()возвращает Object.

Например,

Person p = new Person();
p.setName("Ramkailash");
p.setId(2000001);
button1.setTag(p);
Ramkailash
источник
20

Для веб-разработчиков это, кажется, эквивалентно данным ...

Орен
источник
14

Это очень полезно для пользовательского 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);
    }
            ....................
}
Шуб-Ниггурат
источник
13

В отличие от идентификаторов, теги не используются для идентификации представлений. По сути, теги - это дополнительная часть информации, которая может быть связана с представлением. Чаще всего они используются для удобства хранения данных, связанных с представлениями, в самих представлениях, а не в виде отдельной структуры.

Ссылка: http://developer.android.com/reference/android/view/View.html

Саад Билал
источник
11

Установка тегов действительно полезна, когда у вас есть ListView и вы хотите перерабатывать / повторно использовать представления. Таким образом, 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;
}

источник