Какова основная цель setTag () getTag () методов View? - PullRequest
400 голосов
/ 13 марта 2011

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

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

Ответы [ 7 ]

611 голосов
/ 13 марта 2011

Допустим, вы генерируете несколько похожих представлений.Вы можете установить 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 имеет только один параметр, View, и он должен получать другую информацию из переменных экземпляра или конечных локальных переменных во вложенных областях.Мы действительно хотим получить информацию от самих представлений .

Enter getTag / setTag:

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

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

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

По сути, у представлений есть способ воспоминаний .

117 голосов
/ 14 октября 2013

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

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

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

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

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

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

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

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

25 голосов
/ 21 марта 2014

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

Например,

Person p = new Person();
p.setName("Ramkailash");
p.setId(2000001);
button1.setTag(p);
19 голосов
/ 17 января 2014

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

14 голосов
/ 24 августа 2013

Это очень полезно для пользовательского 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);
    }
            ....................
}
11 голосов
/ 07 марта 2014

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

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

10 голосов
/ 26 июня 2015

Настройка тегов действительно полезна, когда у вас есть 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;
}
...