As of version 19.1 of the Android support library, there is a new annotations package which includes a number of useful metadata annotations you can decorate your own code with, to help catch bugs. The support library itself has also been annotated with these annotations, so as a user of the support library, Android Studio will already check your code and flag potential problems based on these annotations. As of version 22.2 of the support library, there are an additional 13 new annotations you can also use.
The annotations are not included by default; they are shipped as a separate library. (The support library is now made up of a number of smaller libraries: v4-support, appcompat, gridlayout, mediarouter, and so on.)
(If you're using the appcompat library, you already have access to the annotations, because appcompat itself depends on it.)
The easiest way to add the annotations is to just open the Project Structure Dialog. First select your module on the left, then on the right select the Dependencies tab, click on the + button at the bottom of the panel, select Library Dependency, and assuming you have the Android Support Repository installed in your SDK, the support annotation library will be one of the prepopulated links in the list you can just click on (it's the first element in the list) :
Hit OK to finish editing the project structure. This will edit your build.gradle file as follows, which you can also do by hand:
For Android application and Android library modules (e.g. when you're using apply plugin: 'com.android.application' or 'com.android.library') that's all you need to do. If you'd like to use these annotations in a Java-only module, you'll also need to include the SDK repository explicitly, since the support libraries are not available from jcenter (the Android Gradle plugins automatically include these for dependencies, but the Java plugin does not.)
When you're using Android Studio and IntelliJ, the IDE will flag calls where you are passing the wrong type of parameter to methods annotated with these annotations.
As of version 1.3.0-beta1 of the Gradle plugin, and with the Android M Preview platform tools installed, these checks are also checked/enforced on the command line by the "lint" gradle task. This is useful if you want to flag problems as part of your continuous integration server. NOTE: That does not incude the nullness annotations. All the other annotations in this document are checked by lint.)
If a local variable is known to be null (for example because some earlier code checked whether it was null), and you pass that as a parameter to a method where that parameter is marked as
Example from FragmentActivity in the v4 support library:
(If you use the Analyze > Infer Nullity action, or if you type in @NotNull instead of @NonNull, the IDE may offer to attach the IntelliJ annotations. See the "IntelliJ Annotations" section at the bottom for more.)
Note that @NonNull and @Nullable are not opposites: there is a third option: unspecified. When you don’t specify @NonNull or @Nullable, the tools are not certain, and won’t flag uses of this API.
Initially, we annotated findViewById as @Nullable, and technically, that’s correct: findViewById can return null. But it won’t return null if you know what you’re doing (if you pass it an id that is known to exist in the given context). When we annotated it @Nullable, it meant that a lot of code (which did not null check every findViewById call) would light up in the source editor with warnings. Only use @Nullable on a return value if you’re prepared to say that every use of the method should be explicitly null checked. As a rule of thumb: Take a look at existing “good code” (e.g. code reviewed production code) to see how the API is being used. If that code is null checking the results, you should probably mark the method @Nullable.
Resources in Android are typically passed around as integers. That means code which expects a parameter to refer to a drawable can easily be passed a reference to a string; they are both of type
The resource type annotations allow you to add some type checking on top of this. By annotating an int parameter with
Example from ActionBar:
There are many different resource type annotations: one for each Android resource type:
In addition, there is a special resource annotation called
Note that if your API supports multiple resource types, you can put more than one of these annotations on your parameter.
IntDef/StringDef: Typedef Annotations
In addition to passing ints around to represent resource references, ints are often passed around where they are intended to be used as "enums" instead.
The @IntDef annotation lets you basically create a "typedef", where you create another annotation which represents the valid integer constants that you expect, and then you decorate your API with this typedef annotation.
Here's an example from the appcompat support library:
The non-bold parts above was the existing API. We create a new annotation (that's what the above line "
With this annotation, the IDE will flag cases where you pass a different integer in to the method, or check the return value for constants other than the specified ones.
You can also specify that an integer can be a flag; that means client code will be allowed to pass in multiple constants combined using |, & etc:
Finally, there is a String-version of this annotation, @StringDef, which is used for the same purpose but for strings. This is not nearly as common, but it serves the very useful purpose of defining the allowed set of constants you can pass to Activity#getSystemService.
For more details on the typedef annotations, see
(This is closely based on IntelliJ's MagicConstant annotation; you can find more information about that annotation here: http://blog.jetbrains.com/idea/2012/02/new-magic-constant-inspection/ )
(Support library 22.2 and later.)
If your method should only be called from a specific type of thread, you can annotate it with one of these 4 annotations:
If all methods in a class share the same threading requirement, you can annotate the class itself. This is the case for android.view.View for example, which is annotated with @UiThread.
A good example for a usage of the threading annotations is AsyncTask:
If you attempt to call onProgressUpdate from a method which overrides doInBackground, or if you call into any View method, the tools will now flag this as an error:
There is one and only one main thread in the process. That's the @MainThread. That thread is also a @UiThread. This thread is what the main window of an activity runs on, for example. However it is also possible for applications to create other threads on which they run different windows. This will be very rare; really the main place this distinction matters is the system process. Generally you'll want to annotate methods associated with the life cycle with @MainThread, and methods associated with the view hierarchy with @UiThread. Since the @MainThread is a @UiThread, and since it's usually the case that a @UiThread is the @MainThread, the tools (lint, Android Studio, etc) treat these threads as interchangeable, so you can call @UiThread methods from @MainThread methods and vice versa.
RGB Color Integers
You can specify @ColorRes when your API expects a color resource, but that won’t help when you have the opposite scenario: your API doesn’t expect a color resource id, but an actual RGB or ARGB color integer.
In that case, you can use the @ColorInt annotation, which states that an integer is expected to represent a color integer:
With this, lint will flag incorrect code which passes a color id rather than a color:
If your parameter is a float or double, and must be in a certain range, you can use the @FloatRange annotation:
If somebody is under the impression that your API takes a value from 0 - 255 and tries to call setAlpha(128), the tools will catch this:
(You can also specify whether the starting and ending values are inclusive or exclusive.)
Similarly, if your parameter is an int or long, you can use the @IntRange annotation to constrain the value to a particular integer range:
This annotation is most useful when applied to parameters where users are likely to get the range wrong, such as the example above where some APIs take alpha to be a value from 0-255 and others a float from 0-1.
Finally, for arrays, collections and Strings, you can use the @Size parameter to specify constraints on the size of the collection (or in the case of Strings, the length of the strings).
This lets you say for example that a
If your method call requires the caller to hold precisely one permission, you can use the @RequiresPermission annotation like this:
If you require at least one from a set of permissions, you can use the anyOf attribute:
If you require multiple permissions, use the allOf attribute:
For permissions on intents, place the permission requirement on the String field which defines the intent constant (these normally are already annotated with @SdkConstant) :
For permissions on content providers, you probably need separate permissions for read and write access, so wrap each permission requirement in a @Read or @Write annotation:
If your API allows callers to override a method, but you need your own method to be invoked from any overriding methods as well, you can annotate the method with @CallSuper:
With this, the tools will immediately flag overriding code that fails to invoke the super method:
(There was a bug in this lint check when running inside the IDE in Android Studio 1.3 Preview 1 which caused it to report error on perfectly valid overriding methods. That bug has been fixed in Preview 2, now available in the canary channel.)
If your method is returning a value that callers are expected to do something with, annotate the method with @CheckResult.
You don’t need to go and annotate every single non-void method with this annotation. It’s main purpose is to help with cases where users of the API may be confused and may think that the method has a side effect.
For example, many new Java developers are confused by String.trim(), believing that calling that method will cause the string to be changed to remove whitespace. If that method is annotated with @CheckResult, the tools will flag uses of String.trim() where the caller does not actually do something with the result of the trim() call.
In Android, one API which has already been annotated with @CheckResult is Context#checkPermission:
This is important because some developers were calling context.checkPermission and believing that they had enforced a permission -- but that method only checks and returns a result for whether it was successful. Anyone calling that method without looking at the return value probably intended to call Context#enforcePermission instead.
Technical docs >