Qual é o principal objetivo dos métodos setTag () getTag () do View?

421

Qual é o objetivo principal de métodos como setTag()e getTag()de Viewobjetos de tipo?

Estou certo ao pensar que posso associar qualquer número de objetos a uma única visualização?

Eugene
fonte

Respostas:

636

Digamos que você gere várias visualizações semelhantes. Você pode definir um OnClickListenerpara cada visualização individualmente:

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

Então você deve criar um onClickmétodo exclusivo para cada visualização, mesmo que eles façam o mesmo, como:

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

Isso ocorre porque onClickpossui apenas um parâmetro, a View, e precisa obter outras informações de variáveis ​​de instância ou variáveis ​​locais finais nos escopos anexos. O que realmente queremos é obter informações dos próprios pontos de vista .

Digite getTag/ setTag:

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

Agora podemos usar o mesmo OnClickListener para cada botão:

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

É basicamente uma maneira de as visualizações terem memórias .

Matthew Willis
fonte
8
@ Matthew Willis, mas podemos fazer isso usando o view.getId () também. não é ?
Android Killer
50
@AndroidKiller você poderia, mas com setTag () você pode colocar qualquer objeto que você deseja, até mesmo classes personalizadas - para que você possa usá-los a persistir uma referência aos dados que a visão está exibindo
Daniel
O que devo fazer se quiser alterar apenas a cor de fundo do botão clicado ??? Estou recebendo a posição por getTag ().
Sagar Devanga
2
@ Sagar: public void ui_click(View view){ if(20==((int)view.getTag())) view.setBackgroundColor(colorInt); }deve fazer o truque para a parte da cor. 20 é apenas um espaço reservado para a posição de validação da sua visualização.
21316 RiA
Eu acho que esse é o jeito antigo. a nova maneira é usar argumentos genéricos que fornecem segurança de tipo. mas isso é bom, no entanto.
M.kazem Akhgary
124

Eu gostaria de adicionar algumas palavras.

Embora o uso get/setTag(Object)pareça ser muito útil no caso específico de um padrão ViewHolder, recomendo pensar duas vezes antes de usá-lo em outros casos. Quase sempre há outra solução com melhor design.

A principal razão é que um código como esse se torna insuportável rapidamente.

  • Não é óbvio para outros desenvolvedores o que você projetou para armazenar como tag na exibição. Os métodos setTag/getTagnão são descritivos.

  • Ele apenas armazena um Object, que precisa ser convertido quando você desejar getTag. Você pode obter falhas inesperadas mais tarde quando decide alterar o tipo de objeto armazenado na tag.

  • Aqui está uma história da vida real: tivemos um projeto bastante grande com muitos adaptadores, operações assíncronas com visualizações e assim por diante. Um desenvolvedor decidiu set/getTagem sua parte do código, mas outro já havia definido a tag para essa visualização. No final, alguém não conseguiu encontrar sua própria etiqueta e ficou muito confuso. Nos custou várias horas para encontrar o bug.

setTag(int key, Object tag)parece muito melhor, pois você pode gerar chaves exclusivas para cada tag (usando recursos de identificação ), mas há uma restrição significativa para o Android <4.0. Dos documentos do Lint:

Antes do Android 4.0, a implementação do View.setTag (int, Object) armazenava os objetos em um mapa estático, onde os valores eram fortemente referenciados. Isso significa que, se o objeto contiver referências que apontem para o contexto, o contexto (que aponta para praticamente todo o resto) vazará. Se você passar por uma visão, a visão fornecerá uma referência ao contexto que a criou. Da mesma forma, os detentores de exibição geralmente contêm uma exibição, e os cursores também são associados às visualizações.

Andrei Buneyeu
fonte
2
Obrigado, muito útil! ... Você sabe se o que está na tag é restaurado entre as recriações de atividades?
Gunar
25

Podemos usar setTag()e getTag()definir e obter objetos personalizados conforme nossa exigência. O setTag()método pega um argumento do tipo Objecte getTag()retorna um Object.

Por exemplo,

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

Para desenvolvedores web, isso parece ser o equivalente a dados ..

Oren
fonte
14

Isso é muito útil para ArrayAdapteruso personalizado . É algum tipo de otimização. É setTagusado como referência ao objeto que faz referência em algumas partes do layout (que são exibidas ListView) em vez de 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);
    }
            ....................
}
shubniggurath
fonte
13

Ao contrário dos IDs, as tags não são usadas para identificar visualizações. As tags são essencialmente uma informação extra que pode ser associada a uma exibição. Eles costumam ser usados ​​como uma conveniência para armazenar dados relacionados às visualizações nas próprias visualizações, em vez de colocá-los em uma estrutura separada.

Referência: http://developer.android.com/reference/android/view/View.html

Saad Bilal
fonte
11

A configuração de TAGs é realmente útil quando você possui um ListView e deseja reciclar / reutilizar as visualizações. Dessa forma, o ListView está se tornando muito semelhante ao RecyclerView mais recente.

@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;
}

fonte