Wednesday, August 30, 2017

Android Annotation Working of @IdRes

Leave a Comment

I was using setId method of View class. According to this method

public void setId(@IdRes int id) // This will accept resource id 

When I tried to use this method with some hardcoded int value(let say 100), then this method start throwing correct warning which is expected-

actionButton.setId(100); 

Expected resource of type id.

But when I converted this hardcoded value into a method and never defined that this method will return @IdRes, Warning gets silent.

    private int getViewId() {         return 100;     } 

Method call to set Id.

 actionButton.setId(getViewId()); 

Isn't both are same. Hardcoded int and a int return from this method. So why in one case method throwing warning and in another it gets silent.

For a sake I tried with StringRes but I am getting warning in both cases.

 private void setMyString(@StringRes int resourceString) {} 

Warning in both below cases-

    setMyString(1);     setMyString(getStringId()); getStringId returns int value 

2 Answers

Answers 1

It is just a Lint warning since the method expects a variable to be from R.id class.

Regarding the case of value returned from a method, Lint doesn't bother to check the whole function whether it is returning a hardcoded integer or an actual id.

From the documentation of @IdRes it states:

Denotes that an integer parameter, field or method return value is expected to be an id resource reference (e.g. android.R.id.copy).

Also the annotation just exist in the source code for documentation. After the code is compiled, the annotation will be removed.

Answers 2

In one case (@IdRes) you are calling a method from the API (View.setId()), while in the other, you are calling a method in your own code. Also getViewId() is not annotated, so it is not obvious from the signature what kind of int it returns.

With the following methods :

private int getUndefinedRes() {    ... }  private @IdRes int getIdRes() {    ... }  private @StringRes int getStringRes() {     ... }  private void setMyString(@StringRes int resourceString) { }  private void setMyId(@IdRes int resourceId) { } 

The lint and inspection results are (as of Android Studio 2.3.3) :

    // API method with definitely wrong value (constant)     // --> ERROR     new View(context).setId(100);     new TextView(context).setText(100);      // API method with definitely wrong value (from method declaration)     // --> ERROR     new View(context).setId(getStringRes());     new TextView(context).setText(getIdRes());      // API method with potentially wrong value     // --> ok     new View(context).setId(getUndefinedRes());     new TextView(context).setText(getUndefinedRes());      // own method with potentially wrong value     // --> ERROR     setMyString(getUndefinedRes());     setMyId(getUndefinedRes()); 

It seems that the lint only looks at the method signature.

It is also more lenient when you call an API method : it shows an error only if it is obvious that you are doing something wrong. I think that it's because doing otherwise would force everybody to add a lot of annotations.

On the other hand, when you add annotations in your code, you are opting in for the additionnal severity.

If You Enjoyed This, Take 5 Seconds To Share It

0 comments:

Post a Comment