Was ist der Hauptzweck der setTag () getTag () -Methoden von View?


420

Was ist der Hauptzweck von Methoden wie setTag()und getTag()von ViewTypobjekten?

Habe ich Recht, wenn ich denke, dass ich einer einzelnen Ansicht eine beliebige Anzahl von Objekten zuordnen kann?

Antworten:


635

Angenommen, Sie generieren eine Reihe ähnlicher Ansichten. Sie können OnClickListenerfür jede Ansicht einzeln eine festlegen :

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

Dann müssen Sie onClickfür jede Ansicht eine eindeutige Methode erstellen, auch wenn sie ähnliche Aktionen ausführen, z.

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

Dies liegt daran, dass onClicknur ein Parameter a vorhanden Viewist und andere Informationen von Instanzvariablen oder endgültigen lokalen Variablen in umschließenden Bereichen abgerufen werden müssen. Was wir wirklich wollen, ist, Informationen aus den Ansichten selbst zu erhalten .

Geben Sie getTag/ setTag:

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

Jetzt können wir für jede Schaltfläche denselben OnClickListener verwenden:

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

Es ist im Grunde eine Möglichkeit für Ansichten, Erinnerungen zu haben .


8
@ Matthew Willis, aber wir können das auch mit view.getId () tun. nicht wahr ?
Android Killer

50
@AndroidKiller könnten Sie, aber mit setTag () können Sie jedes gewünschte Objekt setzen, auch benutzerdefinierte Klassen - so können Sie sie verwenden, um einen Verweis auf die Daten beizubehalten, die die Ansicht anzeigt
Daniel

Was soll ich tun, wenn ich nur die Hintergrundfarbe der angeklickten Schaltfläche ändern möchte? Ich bekomme die Position von getTag ().
Sagar Devanga

2
@Sagar: public void ui_click(View view){ if(20==((int)view.getTag())) view.setBackgroundColor(colorInt); }sollte den Trick für den Farbteil machen. 20 ist nur ein Platzhalter für die Validierungsposition Ihrer Ansicht.
RiA

Ich denke das ist der alte Weg. Der neue Weg besteht darin, generische Argumente zu verwenden, die Typensicherheit bieten. aber das ist trotzdem gut.
M. Kazem Akhgary 5.

124

Ich möchte ein paar Worte hinzufügen.

Obwohl die Verwendung get/setTag(Object)im speziellen Fall eines ViewHolder-Musters sehr nützlich zu sein scheint, würde ich empfehlen, zweimal darüber nachzudenken, bevor Sie es in anderen Fällen verwenden. Es gibt fast immer eine andere Lösung mit besserem Design.

Der Hauptgrund ist, dass solcher Code ziemlich schnell nicht mehr unterstützt werden kann.

  • Für andere Entwickler ist es nicht offensichtlich, was Sie als Tag in der Ansicht speichern möchten. Die Methoden setTag/getTagsind überhaupt nicht beschreibend.

  • Es speichert nur eine Object, die gegossen werden muss, wenn Sie möchten getTag. Sie können später zu unerwarteten Abstürzen kommen, wenn Sie den Typ des im Tag gespeicherten Objekts ändern.

  • Hier ist eine reale Geschichte: Wir hatten ein ziemlich großes Projekt mit vielen Adaptern, asynchronen Operationen mit Ansichten und so weiter. Ein Entwickler entschied sich für set/getTagseinen Teil des Codes, aber ein anderer hatte das Tag bereits auf diese Ansicht gesetzt. Am Ende konnte jemand sein eigenes Etikett nicht finden und war sehr verwirrt. Es hat uns mehrere Stunden gekostet, den Fehler zu finden.

setTag(int key, Object tag)sieht viel besser aus, da Sie für jedes Tag eindeutige Schlüssel generieren können (mithilfe von ID-Ressourcen ), aber für Android <4.0 gibt es eine erhebliche Einschränkung. Aus Lint-Dokumenten:

Vor Android 4.0 wurden bei der Implementierung von View.setTag (int, Object) die Objekte in einer statischen Karte gespeichert, auf die stark verwiesen wurde. Dies bedeutet, dass, wenn das Objekt Verweise enthält, die auf den Kontext verweisen, der Kontext (der auf so ziemlich alles andere verweist) ausläuft. Wenn Sie eine Ansicht übergeben, enthält die Ansicht einen Verweis auf den Kontext, in dem sie erstellt wurde. In ähnlicher Weise enthalten Ansichtsinhaber normalerweise eine Ansicht, und Cursor werden manchmal auch Ansichten zugeordnet.


2
Danke, sehr hilfreich! ... Wissen Sie zufällig, ob das, was sich im Tag befindet, zwischen den Aktivitätserstellungen wiederhergestellt wird?
Gunar

25

Wir können benutzerdefinierte Objekte gemäß unseren Anforderungen verwenden setTag()und getTag()festlegen und abrufen. Die setTag()Methode verwendet ein Argument vom Typ Objectund getTag()gibt ein zurück Object.

Zum Beispiel,

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

20

Für Webentwickler scheint dies das Äquivalent zu Daten zu sein.


14

Dies ist sehr nützlich für die benutzerdefinierte ArrayAdapterVerwendung. Es ist eine Art Optimierung. Es setTagwird als Referenz auf ein Objekt verwendet, das auf einige Teile des Layouts (die in angezeigt werden ListView) verweist, anstatt 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

Im Gegensatz zu IDs werden Tags nicht zum Identifizieren von Ansichten verwendet. Tags sind im Wesentlichen zusätzliche Informationen, die einer Ansicht zugeordnet werden können. Sie werden am häufigsten verwendet, um Daten zu Ansichten in den Ansichten selbst zu speichern, anstatt sie in einer separaten Struktur abzulegen.

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


11

Das Festlegen von TAGs ist sehr nützlich, wenn Sie eine ListView haben und die Ansichten recyceln / wiederverwenden möchten. Auf diese Weise wird die ListView der neueren RecyclerView sehr ähnlich.

@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;
}
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.