151

Why do I get this Exception?

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)

the line in question is:

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

and I have it defined as:

private static final int TAG_ONLINE_ID = 1;
Pentium10
  • 204,586
  • 122
  • 423
  • 502

10 Answers10

236

The reason you're not able to use setTag(int, Object) is because android require a pre-compiled unique id in the 'int' argument.

Try creating two unique entry in String.xml xml say, "firstname" & "secondname" & use them as below

imageView.setTag(R.string.firstname, "Abhishek");
imageView.setTag(R.string.lastname, "Gondalia");
ABDroids
  • 3,235
  • 3
  • 20
  • 9
  • 134
    add this to your strings.xml file: and you can use like a regular id resource: R.id.TAG_ONLINE_ID – EtienneSky Dec 23 '11 at 08:10
  • 9
    this one should be the answer. its more generic. – IronBlossom Jul 12 '12 at 07:42
  • This will create an issue if you are using localization in strings – Ajith M A May 22 '13 at 04:49
  • 2
    @AjithMemana why? When the app is compiled, the strings.xml file assigns a unique int resource id to each element. The value of the string element isn't taken into account. – ataulm Jun 30 '13 at 19:59
  • @ataulm Well i am not sure why. I did the same in one of the apps and One of my friends who did the localisation part was experiencing issues when he did localisation. – Ajith M A Jul 01 '13 at 11:46
  • @AjithMemana unless you're sure (where "sure" should include an understanding of "why"), it might be best not to state absolutes like "**this will** create an issue" - I am interested in investigating if you still have the code available (away from this comment thread). If you Google my username, you can find a myriad of contact points for me. – ataulm Jul 01 '13 at 13:33
  • 1
    Thank you, that is so great and helpful ... also if you want to get the tag you need to access strings values like v.getTag(R.string.name) – Amt87 Feb 06 '14 at 10:42
  • 5
    Better create a filename **ids.xml** in **res/values** directory and add there all your unique ids. – vovahost Apr 16 '15 at 14:06
  • 1
    @vovahost Good thinking, I did pretty much the same but called it tags.xml – dumazy Mar 23 '17 at 10:50
160

I'm a little late to the party but I stumbled on this problem myself today and thought I'd give an answer as well. This answer will be a bit of a compilation of the other answers, but with a twist. First of all, the id, as has been pointed out by others, can NOT be a constant defined in your code (such as private static final int MYID = 123) or any other int that you define as a field somewhere.

The id has to be a precompiled unique id, just like the ones you get for strings that you put in values/strings.xml (ie R.string.mystring). Refer to http://developer.android.com/guide/topics/resources/available-resources.html and http://developer.android.com/guide/topics/resources/more-resources.html for more information.

My suggestion is that you create a new file called values/tags.xml and write:

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

I think it's better to create a separate file instead of putting it in strings.xml as EtienneSky suggested.

loeschg
  • 29,961
  • 26
  • 97
  • 150
britzl
  • 10,132
  • 7
  • 41
  • 38
59

THIS WILL DO THE JOB...

If you just have 1 setTag in your class, you could use any int, maybe static final declared in the top.

The problem comes when you had 2 or more setTag's with different keys. I mean:

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

That scenario is wrong. You then need to add a value file called maybe ids.xml with the following:

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

Then, in your class, call:

 ...
 setTag(R.id.resourceDrawable, VALUE_1)
 setTag(R.id.imageURI, VALUE_2)
 ...
Bruno Bieri
  • 9,724
  • 11
  • 63
  • 92
Sterling Diaz
  • 3,789
  • 2
  • 31
  • 35
55

The tag id must be unique so it wants it to be an id created in a resources file to guarantee uniqueness.

If the view will only contain one tag though you can just do

setTag(objContact.onlineid);
Robby Pond
  • 73,164
  • 16
  • 126
  • 119
  • 4
    i still don't get the pattern. i want to set two tags corresponding to say a first and last name. where do i define the integer IDs for these? – Jeffrey Blattman May 26 '11 at 01:04
  • 7
    You can use any resource - even just take a random R.id.FOO where FOO is some id in your project. – Artem Russakovskii Aug 31 '11 at 22:34
  • 21
    That's the best way to get unique tag id ? Really Android ? – jimmy0251 Mar 13 '15 at 10:24
  • Hey there, what if I don't know how many tags are? because I want to generate views according to some data in model.... – jsina Apr 11 '16 at 12:03
  • A possible solution to asker's problem, but is not the best solution. Should not be marked as the answer... – angryITguy Aug 02 '16 at 03:47
  • It is strange, because `setTag` method documentation declares the opposite: `A tag can be used to mark a view in its hierarchy and does not have to be unique within the hierarchy. ` – Zon Sep 25 '18 at 15:15
  • @Zon the tag itself doesn't need to be unique, but the `key` that use for a tag is the one that needs to be unique integer (for some reason) – Bhargav Sep 25 '20 at 12:22
8
private static final int TAG_ONLINE_ID = 1 + 2 << 24;

should work. More info from ceph3us:

The specified key should be an id declared in the resources of the application to ensure it is unique Keys identified as belonging to the Android framework or not associated with any package will cause an IllegalArgumentException to be thrown.

from source:

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);
}
Community
  • 1
  • 1
Anton Duzenko
  • 2,366
  • 1
  • 21
  • 26
  • Because the ID has to be one generated in your R.java file. – StackOverflowed Aug 17 '13 at 14:25
  • No, it does not. It has to be greater than 2 << 24, that's all. – Anton Duzenko Aug 17 '13 at 20:28
  • Well, the 1 + 2 << 24, 2 + 2 << 24 etc approach actually works. Looks like an irregular fix. I like to know why it is like this? Are there any risks, for instance in future versions of Android etc? It is by far smother to use it defined as a constant? – Jan Bergström Feb 16 '16 at 22:48
  • Because it is hardcoded in Android SDK. It won't change ever because otherwise all existing android apps will stop working. – Anton Duzenko Feb 17 '16 at 07:07
  • OK, technically it is sustainable. Are there any political issues making people vote negative for this solution? Is there a policy that the ID has to be one generated in your R.java file, from where (can I read it). – Jan Bergström Feb 18 '16 at 02:01
  • If there was, there would be a comment about it. No comment means the downvotes are most likely irrational/based on professional prejudices. – Anton Duzenko Feb 18 '16 at 08:46
  • setTag considers “id” anything bigger than 0x03000000. So this solution works. I don’t know the reason for this restriction, as at the end its saved at a normal SparseArray and it has no sense in needing a resource-id. Hopefully they will remove this in the future – Corbella Mar 02 '16 at 17:42
  • And yet at least three users _silently_ downvoted it - I wonder if it was the original programmer of setTag and his family members – Anton Duzenko Mar 02 '16 at 21:33
  • Because it is dirty hack based on internal implementation. In newer version it can be changed if google do not stay backward compability. In theory it can happen. – Enyby May 14 '16 at 22:05
  • Is deliberately breaking all existing apps in Play Market a valid theory for you? Don't forget to mention that at your next job interview. – Anton Duzenko May 15 '16 at 15:54
  • 1
    I guess the main problem in this solution is that it does not guarantee uniqness of this key, which means that by adding some library or other code that is using setTag feature this logic can break if generated id will match one got from this solution. – EdgarK Sep 27 '16 at 19:30
3

I've used viewHolder.itemTitleTextView.getId(). But you can also declare in your resources: <item type="id" name="conversation_thread_id"/>

ViliusK
  • 11,345
  • 4
  • 67
  • 71
2

you can use this :

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

for uniqness application-specific resource id

Jackie Cheng
  • 190
  • 1
  • 9
0

This works for me:

setTag(0xffffffff,objContact.onlineid);
yu xiaofei
  • 55
  • 5
0

The reason why you want to save the value by an id is, that you want to cover more than one value in this tag, right?
Here a more simple solution:
Let's say you want to save two values (Strings) into this tag: "firstname" and "lastname". You can save them both in one string, separated by semicolon:

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

... and access them by splitting them into an string array:

String[] data = v.getTag().toString().split(";");
System.out.println(data[0]) //firstname
System.out.println(data[1]) //lastname
0

Here is a simple workaround that works for me:

int tagKey = "YourSimpleKey".hashCode();

myView.setTag(tagKey, "MyTagObject");

the important clue here is to call .hashCode(); on the String

kc ochibili
  • 3,103
  • 2
  • 25
  • 25