Klucz musi być identyfikatorem zasobu specyficznym dla aplikacji

145

Dlaczego otrzymuję ten wyjątek?

05-18 20:29:38.044: ERROR/AndroidRuntime(5453): java.lang.IllegalArgumentException: The key must be an application-specific resource id.
05-18 20:29:38.044: ERROR/AndroidRuntime(5453):     at android.view.View.setTag(View.java:7704)
05-18 20:29:38.044: ERROR/AndroidRuntime(5453):     at com.mypkg.viewP.inflateRow(viewP.java:518)

przedmiotowa linia to:

((Button) row.findViewById(R.id.btnPickContact)).setTag(TAG_ONLINE_ID,objContact.onlineid);

i mam to zdefiniowane jako:

private static final int TAG_ONLINE_ID = 1;
Pentium10
źródło

Odpowiedzi:

55

Identyfikator tagu musi być unikalny, więc chce, aby był to identyfikator utworzony w pliku zasobów w celu zagwarantowania unikalności.

Jeśli widok będzie zawierał tylko jeden tag, możesz to zrobić

setTag(objContact.onlineid);
Robby Pond
źródło
3
nadal nie rozumiem wzoru. Chcę ustawić dwa tagi odpowiadające imieniu i nazwisku. gdzie mogę zdefiniować identyfikatory całkowite dla tych?
Jeffrey Blattman
7
Możesz użyć dowolnego zasobu - nawet po prostu weź losowy R.id.FOO, gdzie FOO to jakiś identyfikator w Twoim projekcie.
Artem Russakovskii
16
To najlepszy sposób na uzyskanie unikalnego identyfikatora tagu? Naprawdę Android?
jimmy0251
Hej, a co jeśli nie wiem, ile jest tagów? ponieważ chcę generować widoki na podstawie niektórych danych w modelu ....
jsina Kwietnia
Możliwe rozwiązanie problemu pytającego, ale nie jest to najlepsze rozwiązanie. Nie należy oznaczać jako odpowiedzi ...
angryITguy
226

Powodem, dla którego nie możesz użyć setTag (int, Object), jest to, że Android wymaga prekompilowanego unikalnego identyfikatora w argumencie „int”.

Spróbuj utworzyć dwa unikalne wpisy w String.xml xml, powiedz „imię” i „drugie imię” i użyj ich jak poniżej

imageView.setTag(R.string.firstname, "Abhishek");
imageView.setTag(R.string.lastname, "Gondalia");
ABDroids
źródło
129
dodaj to do swojego pliku strings.xml: <item type = "id" name = "TAG_ONLINE_ID" /> i możesz używać go jak zwykłego zasobu identyfikatora: R.id.TAG_ONLINE_ID
EtienneSky
9
ten powinien być odpowiedzią. jego bardziej ogólne.
IronBlossom,
2
@AjithMemana dlaczego? Gdy aplikacja jest kompilowana, plik strings.xml przypisuje każdemu elementowi unikalny identyfikator zasobu int. Wartość elementu string nie jest brana pod uwagę.
ataulm
1
Dziękuję, to jest świetne i pomocne ... także jeśli chcesz uzyskać tag, musisz uzyskać dostęp do wartości ciągów, takich jak v.getTag (R.string.name)
Amt87,
5
Lepiej utwórz nazwę pliku ids.xml w katalogu res / values i dodaj tam wszystkie swoje unikalne identyfikatory.
vovaost
146

Trochę się spóźniłem na imprezę, ale sam dzisiaj natknąłem się na ten problem i pomyślałem, że też dam odpowiedź. Ta odpowiedź będzie trochę kompilacją innych odpowiedzi, ale z pewnym elementem. Po pierwsze, id, jak wskazywali inni, NIE może być stałą zdefiniowaną w Twoim kodzie (np. Private static final int MYID = 123) ani żadną inną wartością typu int, którą zdefiniujesz gdzieś jako pole.

Identyfikator musi być prekompilowanym unikalnym identyfikatorem, tak jak te, które otrzymujesz dla łańcuchów, które umieszczasz w value / strings.xml (tj. R.string.mystring). Więcej informacji znajdziesz na http://developer.android.com/guide/topics/resources/available-resources.html i http://developer.android.com/guide/topics/resources/more-resources.html .

Moja sugestia jest taka, aby utworzyć nowy plik o nazwie values ​​/ tags.xml i napisać:

    <resources xmlns:android="http://schemas.android.com/apk/res/android">
      <item name="TAG_ONLINE_ID" type="id"/>
    </resources>

Myślę, że lepiej jest utworzyć osobny plik zamiast umieszczać go w strings.xml, jak sugerował EtienneSky.

britzl
źródło
14
Możesz nawet <item name="TAG_ONLINE_ID" type="id"/>uprościć to.
Benoit Duffez,
To jest prawdziwe rozwiązanie; Nie nowicjusz „Nie rozumiem, co robię, ale ten hack działa”
Roel
uwaga, aby uzyskać dostęp w użyciu kodu R.id..., a nie R.string.. lubR.tags...
g2server
Było to przydatne, a oto kolejny post, w którym pokazuje jego użycie: stackoverflow.com/questions/28492493/ ...
prasad_
I upewnij się, że umieściłeś plik w wartościach, a nie w folderze xml. :)
Nantoka
55

TO WYKONUJE PRACĘ ...

Jeśli masz tylko 1 setTag w swojej klasie, możesz użyć dowolnego typu int, może statycznego final zadeklarowanego na górze.

Problem pojawia się, gdy masz 2 lub więcej setTagów z różnymi kluczami. Mam na myśli:

public static final int KEY_1 = 1;
public static final int KEY_2 = 2;
...
setTag(KEY_1)
setTag(KEY_2)
...

Ten scenariusz jest zły. Następnie musisz dodać plik wartości o nazwie może ids.xml z następującymi elementami:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <item type="id" name="resourceDrawable" />
    <item type="id" name="imageURI" />
</resources>

Następnie w klasie zadzwoń:

 ...
 setTag(R.id.resourceDrawable, KEY_1)
 setTag(R.id.imageURI, KEY_2)
 ...
Sterling Diaz
źródło
najlepsze wytłumaczenie dla nowicjuszy
Richard Le Mesurier
To jest prawdziwe rozwiązanie: nie naprawa hacka dla początkujących!
Roel
8
private static final int TAG_ONLINE_ID = 1 + 2 << 24;

powinno działać. Więcej informacji od ceph3us :

Określony klucz powinien być identyfikatorem zadeklarowanym w zasobach aplikacji, aby upewnić się, że jest unikalny. Klucze zidentyfikowane jako należące do platformy Android lub niepowiązane z żadnym pakietem spowodują wyrzucenie wyjątku IllegalArgumentException.

ze źródła:

public void setTag(int key, final Object tag) {
    // If the package id is 0x00 or 0x01, it's either an undefined package
    // or a framework id
    if ((key >>> 24) < 2) {
        throw new IllegalArgumentException("The key must be an application-specific "
                + "resource id.");
    }

    setKeyedTag(key, tag);
}
Anton Duzenko
źródło
Ponieważ identyfikator musi być wygenerowany w pliku R.java.
StackOverflowed
Nie. Musi być większe niż 2 << 24, to wszystko.
Anton Duzenko
Cóż, podejście 1 + 2 << 24, 2 + 2 << 24 itd. Faktycznie działa. Wygląda na nieregularną poprawkę. Lubię wiedzieć, dlaczego tak jest? Czy są jakieś zagrożenia, na przykład w przyszłych wersjach Androida itp.? O wiele łatwiej jest używać go jako stałej?
Jan Bergström
Ponieważ jest zakodowany na stałe w Android SDK. To się nigdy nie zmieni, ponieważ w przeciwnym razie wszystkie istniejące aplikacje na Androida przestaną działać.
Anton Duzenko
1
Myślę, że głównym problemem w tym rozwiązaniu jest to, że nie gwarantuje ono unikalności tego klucza, co oznacza, że ​​dodając jakąś bibliotekę lub inny kod korzystający z funkcji setTag ta logika może się zepsuć, jeśli wygenerowany identyfikator będzie pasował do tego otrzymanego z tego rozwiązania.
EdgarK
3

Użyłem viewHolder.itemTitleTextView.getId(). Ale możesz również zadeklarować w swoich zasobach: <item type="id" name="conversation_thread_id"/>

ViliusK
źródło
0

To działa dla mnie:

setTag(0xffffffff,objContact.onlineid);
yu xiaofei
źródło
0

Powodem, dla którego chcesz zapisać wartość przez identyfikator, jest to, że chcesz uwzględnić więcej niż jedną wartość w tym tagu, prawda?
Oto prostsze rozwiązanie:
powiedzmy, że chcesz zapisać dwie wartości (ciągi znaków) w tym tagu: „imię” i „nazwisko”. Możesz zapisać je oba w jednym ciągu, oddzielonym średnikiem:

v.setTag(firstname + ";" + lastname);

... i uzyskaj do nich dostęp, dzieląc je na tablicę ciągów:

String[] data = v.getTag().toString().split(";");
System.out.println(data[0]) //firstname
System.out.println(data[1]) //lastname
Johannes Schuh
źródło
0

możesz użyć tego:

private static final int TAG_ONLINE_ID = View.generateViewId() + 2 << 24;

dla unikalności identyfikatora zasobu specyficznego dla aplikacji

Jackie Cheng
źródło