Original address: http://www.flysnow.org/2015/08/13/android-tech-docs-support-annotations.html
Annotation Support (Annotations)
The Android Support Library has introduced a new annotation library from version 19.1, which contains a lot of useful meta-annotations that you can use to decorate your code to help you find bugs. The support library itself uses these annotations, so as a user of the support library, Android Studio has verified your code based on these annotations and annotated the underlying issues. Support Library version 22.2 has added 13 new annotations for use.
Working with annotation libraries
Annotations are not included by default; they are packaged as a separate library. (The support library is now made up of smaller libraries: V4-support, AppCompat, GridLayout, mediarouter, etc.)
(If you are using the AppCompat library, you can already use these annotations, because Appcomat itself relies on it.) )
The simplest way to add an annotation using annotations is to open the Project Structure dialog box. First select the module on the left, then select the Dependencies tab on the right, click the button at the bottom of the panel and +
select the library Dependency, assuming you have the Android support Repository is installed in your SDK, the annotation library will appear in the list, just click to select it (this is the first one in the list):
Add dependency
Click OK to finish editing the project structure. This will modify your Build.gradle file, and of course you can edit it manually:
dependencies { compile ‘com.android.support:support-annotations:22.2.0‘}
For both Android application and Android libraries, the two types of module (which you apply com.android.application
or com.android.library
plug-in), you need to do all the work done. If you want to use these annotations only in the Java module, you explicitly include the SDK repository because the support libraries is not available from Jcenter (the Android Gradle plugin automatically contains these dependencies, but the Java plugin does not.) )
repositories { jcenter() maven { url ‘<your-SDK-path>/extras/android/m2repository‘ }}
Execute annotations
When you use Android Studio and IntelliJ, the IDE is tagged in real time if you pass the wrong type of arguments to the method that labeled the annotations.
These checks can be performed by invoking Gradle's task from the command line, starting with the Gradle plug-in 1.3.0-BETA1 version and installing the Android M Preview platform tool. lint
This is useful if you want to put the tagging problem as part of continuous integration. Description: This does not contain nullness annotations. The other annotations described in this article can be checked through lint.
Nullness Annotations
@Nullable annotations can be used to label a given parameter or return a value that can be null.
Similarly, @NonNull annotations can be used to label a given parameter or the return value cannot be null.
If the value of a local variable is null (for example, because a premature code checks if it is null), and you pass it as a parameter to a method, and the parameter of the method is @nonnull labeled, then the IDE reminds you that you have a potential crash problem.
v4 support library中的FragmentActivity的示例代码:import android.support.annotation.NonNull;import android.support.annotation.Nullable;.../** * Add support for inflating the <fragment> tag. */@Nullable@Overridepublic View onCreateView(String name, @NonNull Context context, @NonNull AttributeSet attrs) {...
(If you do analyze > Infer nullity, or if you replace @nonnull with @notnull as you type, the IDE might provide additional IntelliJ annotations.) Refer to the "IntelliJ Annotations" section at the bottom to learn more)
Note that @nonnull and @nullable are not opposites: there is a third possibility: unspecified. When you do not specify @nonnull or @nullable, the tool cannot be determined, so the API will not work.
Initially, we marked @nullable on the Findviewbyid method, technically, this is correct: Findviewbyid can return null. But if you know what you are doing (if you pass him an existing ID) he will not return null. When we annotate it with @nullable, it means that there will be a lot of code in the source editor with a highlight warning. If you are aware that each use of this method should be explicitly null-checked, then you can only use @nullable to label the return value. There is a rule of thumb: Look at the existing "Good code" (like reviewing the product code) to see how these APIs are being used. If the code is a null check result, you should @nullable for the method annotation.
Resource type annotations
The resource values for Android are usually used with integral type delivery. This means getting a parameter that is used by a drawable, and it can be easily passed to a method that gets a string, because they are all int types and the compiler is difficult to distinguish.
Resource type annotations can provide type checking in this case. For example, an int type parameter that is @stringres, if passed a reference that is not a r.string type, will be labeled by the IDE:
Resource type annotations
Take Actionbar as an example:
import android.support.annotation.StringRes;...public abstract void setTitle(@StringRes int resId);
There are many different resource types for annotations: each of the following Android resource types:
@StringRes, @DrawableRes, @ColorRes, @InterpolatorRes, and so on. In general, if there is a foo
type of resource, then its corresponding resource type annotation is foores.
In addition, there is a special resource type annotation called @anyres. It is used to label an unknown special type of resource, but it must be a resource type. For example, in the framework, it is used, Resources#getResourceName(@AnyRes int resId)
when used, you can use it, you can use it getResources().getResourceName(R.drawable.icon)
, but it is getResources().getResourceName(R.string.app_name)
not getResources().getResourceName(42)
used.
Please note that if your API supports multiple resource types, you can use multiple annotations to annotate your parameters.
Intdef/stringdef: type definition annotations
An integral type can be used as an enum type, in addition to being a reference to a resource.
@IntDef and "typedef" are very similar, you can create another annotation, then use @intdef to specify a list of the integer constants you expect, and finally you can use this defined annotation to decorate your API.
An example in the AppCompat library:
import android.support.annotation.IntDef;...public abstract class ActionBar {...@IntDef({NAVIGATION_MODE_STANDARD, NAVIGATION_MODE_LIST, NAVIGATION_MODE_TABS})@Retention(RetentionPolicy.SOURCE)public @interface NavigationMode {}public static final int NAVIGATION_MODE_STANDARD = 0;public static final int NAVIGATION_MODE_LIST = 1;public static final int NAVIGATION_MODE_TABS = 2;@NavigationModepublic abstract int getNavigationMode();public abstract void setNavigationMode(@NavigationMode int mode);
The non-annotated portion of the above is an existing API. We created a new annotation (navigationmode) and labeled it with @intdef, by @intdef we specified the available constant values for the return value or parameter. We have also added a note that @Retention(RetentionPolicy.SOURCE)
tells the compiler that this new definition does not need to be recorded in the generated. class file (Translator Note: The source-level, the annotation is automatically removed by the compiler when the class file is generated).
With this annotation, the IDE will mark the case if you pass a parameter or return value that is not in the specified constant value.
Type definition Annotations
You can also specify that an integer is a type of token nature, so that the client code passes multiple constants at the same time through the |,& operator:
@IntDef(flag=true, value={ DISPLAY_USE_LOGO, DISPLAY_SHOW_HOME, DISPLAY_HOME_AS_UP, DISPLAY_SHOW_TITLE, DISPLAY_SHOW_CUSTOM})@Retention(RetentionPolicy.SOURCE)public @interface DisplayOptions {}
Finally, there is a string version of the annotation, that is, @stringdef, and @intdef is basically the same, the difference is that it is for the string. This annotation is generally not commonly used, but sometimes very useful, such as when restricting the range of parameters passed to the Activity#getsystemservice method.
To learn more about type annotations, please refer to the
Https://developer.android.com/tools/debugging/annotations.html#enum-annotations
(These are based on IntelliJ's magicconstant annotations, where you can find more information about the note: http://blog.jetbrains.com/idea/2012/02/ new-magic-constant-inspection/)
Thread annotations: @UiThread, @WorkerThread, ...
(supported by Support library 22.2 and later.)
If your method can only be called in the specified thread type, then you can annotate it with the following 4 annotations:
- @UiThread
- @MainThread
- @WorkerThread
- @BinderThread
If all methods in a class have the same thread requirements, then you can annotate the class itself. For example, Android.view.View is labeled with @uithread.
A good example of the use of thread annotations is asynctask:
@WorkerThreadprotected abstract Result doInBackground(Params... params);@MainThreadprotected void onProgressUpdate(Progress... values) {}
If you try to invoke the Onprogressupdate method or any of the view methods in the overridden Doinbackground method, the IDE tool will immediately mark it as an error:
Thread annotations
@UiThread or @mainthread?
There is only one main thread in the process. This is @mainthread. At the same time this thread is also a @uithread. For example, the main window of activity is running on this thread. However, it also has the ability to create other threads for the app. This is rare, and the general feature is the system process. It is usually labeled with the @mainthread, which is related to the life cycle, and is associated with the view hierarchy with @uithread. But since @mainthread is essentially a @uithread, and in most cases @uithread is a @mainthread, tools (lint, Android Studio, etc.) can swap them, So you can call the @uithread method in a place where you can call the @mainthread method, and vice versa.
RGB Color Integral type
When your API expects a color resource, it can be labeled with @colorres, but when you have an opposite usage scenario, this usage is not available because you don't expect a color resource ID, but a real RGB or ARGB color value.
In this case, you can use the @colorint annotation to indicate that you expect an integer value that represents the color:
public void setTextColor(@ColorInt int color)
With this, when you pass a color ID instead of a color value, lint will mark the incorrect code:
Color value Annotations
Value constraints: @Size, @IntRange, @FloatRange
If your parameter is a float or double type and must be within a range, you can use the @floatrange annotation:
public void setAlpha(@FloatRange(from=0.0, to=1.0) float alpha) {
If someone uses the API to pass a value of 0-255, such as trying to invoke Setalpha (128), then the tool catches the problem:
Value constraint annotations
(You can also specify whether to include a starting value.) )
Similarly, if your argument is an int or a long type, you can use the @intrange annotation to constrain its value to a specific range:
public void setAlpha(@IntRange(from=0,to=255) int alpha) { … }
It is useful to apply these annotations to parameters, as the user is likely to provide parameters for the wrong range, such as the Setalpha example above, with some APIs in 0-255, and some with a float value of 0-1.
Finally, for data, collections, and strings, you can use the @size annotation parameter to limit the size of the collection (the length of the string can be qualified when the argument is a string).
Give some examples
- Collection cannot be empty: @Size (min=1)
- The string can have a maximum of 23 characters: @Size (max=23)
- Arrays can have only 2 elements: @Size (2)
- The size of the array must be a multiple of 2 (an array of x/y coordinates getting the position in the example API: @Size (multiple=2)
Value constraint annotations
Permission notes: @RequiresPermission
If the invocation of your method requires the caller to have specific permissions, you can use the @requirespermission annotation:
@RequiresPermission(Manifest.permission.SET_WALLPAPER)public abstract void setWallpaper(Bitmap bitmap) throws IOException;
If you need at least one of the permission sets, you can use the Anyof property:
@RequiresPermission(anyOf = { Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION})public abstract Location getLastKnownLocation(String provider);
If you need multiple permissions at the same time, you can use the AllOf property:
@RequiresPermission(allOf = { Manifest.permission.READ_HISTORY_BOOKMARKS, Manifest.permission.WRITE_HISTORY_BOOKMARKS})public static final void updateVisitedHistory(ContentResolver cr, String url, boolean real) {
For intents permissions, you can label permission requirements directly on the defined intent constant string field (they are usually already labeled @sdkconstant annotations):
@RequiresPermission(android.Manifest.permission.BLUETOOTH)public static final String ACTION_REQUEST_DISCOVERABLE = "android.bluetooth.adapter.action.REQUEST_DISCOVERABLE";
For content providers permissions, you may need to individually annotate read and write access, so you can annotate each permission requirement with @read or @write:
@RequiresPermission.Read(@RequiresPermission(READ_HISTORY_BOOKMARKS))@RequiresPermission.Write(@RequiresPermission(WRITE_HISTORY_BOOKMARKS))public static final Uri BOOKMARKS_URI = Uri.parse("content://browser/bookmarks");
Permission annotations
Method overrides: @CallSuper
If your API allows users to rewrite your method, but you need your own method (the parent method) is also called when rewriting, you can use @callsuper annotations:
@CallSuperprotected void onCreate(@Nullable Bundle savedInstanceState) {
With this, the tool gives the markup hint when the overridden method does not call the parent method:
Method overrides
(The lint check of Android Studio 1.3 Preview 1 has a bug about this annotation, this bug is even the correct rewrite will be error, this bug has been modified in the Preview 2 version, can be canary Channel updated to preview version 2. )
return value: @CheckResult
If your method returns a value and you expect the caller to do something with that value, you can use the @checkresult annotation to annotate the method.
You don't need to label every non-empty method. Its main purpose is to help the users of APIs that are easily confused and difficult to understand.
For example, many developers may have String.Trim () smattering, thinking that by invoking this method, the string can be changed to remove whitespace characters. If this method is @checkresult labeled, the tool warns callers who are not using trim () to return results.
In Android, Context#checkpermission This method has been labeled by @checkresult:
@(suggest="#enforcePermission(String,int,int,String)")public abstract int checkPermission(@NonNull String permission, int pid, int uid);
This is important because some developers who use context.checkpermission think they have implemented a permission-but this method only checks and feeds back a successful value. If the developer uses this method, but does not use its return value, then the developer really wants to invoke this context#enforcepermission method, not checkpermission.
return value
@VisibleForTesting
You can annotate this annotation to classes, methods, or fields so that you can use them when testing.
@Keep
We have also added @keep annotations in the annotations library, but the Gradle plugin is also supported (although it is already in progress). The classes and methods annotated by this annotation will not be confused when confused.
Use annotations in your own library
If you use these annotations in your own library and build the AAR package via Gradle build, the Android Gradle plugin will extract the annotation information in the AAR file for use by clients referencing your library when it is built. In the AAR file you can see a file named Annotations.zip, which records the annotation information, using the extended annotation XML format of the IntelliJ. This is necessary because the. class file cannot contain enough information to handle the above @intdef annotations; Note that we only need to record a reference to the constant, not its value. When and only if your project relies on the annotation library, the Android Gradle plugin executes the extracted annotation task as part of the build. (Note: Only source-reserved annotations are placed in the. aar file; Class-level will be placed in the Classes.jar.) )
IntelliJ annotations
Intellij,android Studio is based on its development, IntelliJ a set of its own annotations, INTDEF analysis is actually reusing magicconstant analysis of the code, IntelliJ Null parsing is useful for a set of well-configured null annotations. If you do analyze > Infer nullity ..., it will try to find all the null constraints and add them. This check sometimes inserts IntelliJ annotations. You can use the search to replace the annotations on the Android annotation library, or you can annotate directly with IntelliJ. The following dependencies can be added in Build.gradle or through the dependencies panel of the Project Structure dialog box:
dependencies { compile ‘com.intellij:annotations:12.0‘}
Android annotation Support (Annotations) (EXT)