The concept of annotations

What are annotations?

Annotations, also known as annotations, are used to provide metadata to code. As metadata, annotations don’t directly affect your code execution, but there are some types of annotations that can actually be used for this purpose. Can be applied to classes, methods, variables, parameters, packages, and so on. Commonly known as a “tag,” this tag can mark classes, methods, variables, parameters, and packages.

For what?

  1. Generate documents;
  2. Identification code, easy to view;
  3. Format checking (compile time);
  4. Annotation processing (compile-time generation of code, XML files, etc.; Run-time reflection resolution; Often used in tripartite frameworks).

classification

  1. Yuan notes

Meta-annotations are annotations that define annotations. Meta-annotations are standard annotations that come with Java, but are used to modify annotations. 2. Built-in standard annotations are annotations that are used in code and are provided by different languages or environments (Java Kotlin Android). After using these annotations, the compiler checks. 3. Custom annotations Users can define annotations according to their own requirements.

Standard notes

Java standard annotations

Meta-annotations will be covered later when we look at custom annotations, but only standard annotations will be covered here.

The name of the describe
@Override Check that the method overrides the parent class’s method correctly. If rewriting errors occur, a compilation error is reported;
@Deprecated Flag obsolete methods. If this method is used, a compile warning is reported;
@SuppressWarnings Instructs the compiler to ignore warnings declared in annotations.
@SafeVarargs Ignore warnings from any method or constructor calls that take arguments as generic variables; (Available in Java 7)
@FunctionalInterface Identifies an anonymous function or functional interface (supported starting in Java 8)

Android annotations library

Support-annotation is a library of annotations provided by Android that works with Android Studio’s built-in code inspection tools to help detect possible problems, such as null pointer exceptions and resource type conflicts.

Add configuration to build.gradle in Module:

Implementation 'com. Android. Support: support - annotations: the version number'Copy the code

Note: If you use the AppCompat library, you don’t need to add a support-Annotations dependency. The AppCompat library already relies on the annotation library. (It is automatically imported when you create a project.)

Null sex annotations

  • @NullableCan be null
  • @NonNullNot null

Used to give whether a variable, parameter, or return value can be NULL.

importandroid.support.annotation.NonNull; .@NonNull // Check if the onCreateView() method itself returns NULL.
    @Override
    public View onCreateView(String name, @NonNull Context context,
      @NonNull AttributeSet attrs) {... }...Copy the code

Resource annotation

This is useful when validating resource types, because Android passes references to resources as integers. If your code needs an argument to reference a particular type of resource, you can pass the code the expected reference type int, but it will actually refer to other types of resources, such as r.string.xxx resources.

There are many resource types in Android, and Android annotations provide annotations for each resource type.

  • AnimatorRes // Animation resources (typically attribute animations)
  • AnimRes // Animation resources (generally view animation)
  • AnyRes // Any type of resource reference, int format
  • ArrayRes // Array resource LLDB.android.R.array.phoneTypes
  • AttrRes // Attribute resource LLDB.android.R.attr.action
  • BoolRes // Boolean resources
  • ColorRes // Color resources
  • DimenRes // Dimension resources
  • DrawableRes // Drawable resource
  • FontRes // Font resources
  • FractionRes // Percentage number resource
  • IdRes/reference/Id
  • IntegerRes // Any integer type resource reference
  • InterpolatorRes // Interpolator resource LLDB.android.R.interpolator.cycle
  • LayoutRes // Layout resources
  • MenuRes // Menu resources
  • NavigationRes // Navigation resources
  • PluralsRes // String collection resource
  • RawRes / / Raw resources
  • StringRes // String resources
  • StyleableRes // Style resources
  • StyleRes // Style resources
  • TransitionRes // Transition animation resources
  • XmlRes / / XML resources
  • use@AnyResYou can specify that the parameters to which such annotations are added can be of any typeRResources.
  • Although it can be used@ColorResSpecify that a parameter should be a color resource, but the system does not recognize color integers (in RRGGBB or AARRGGBB format) as color resources. You can use@ColorIntAnnotation to indicate that a parameter must be a color integer.

Thread annotations

Thread annotations can check whether a method is called from a particular type of thread. The following thread annotations are supported:

  • @MainThread
  • @UiThread
  • @WorkerThread
  • @BinderThread
  • @AnyThread

Note: The build tool treats the @MainThread and @UithRead annotations as interchangeable, so you can call the @UithRead method from the @MainThread method and vice versa. However, if the system application has multiple views on different threads, the interface thread may be different from the main thread. Therefore, you should use @UithRead to annotate methods associated with your application’s view hierarchy and @MainThread to annotate only methods associated with your application’s life cycle.

If all the methods in a class have the same threading requirements, you can add a threading annotation to the class to verify that all the methods in the class are called from the same type of thread.

Value constraint annotation

Value constraint annotations verify that the value of the passed parameter is within the specified range:

  • @IntRange
  • @FloatRange
  • @Size

@intrange and @floatRange are most useful when applied to parameters where the user might be in the wrong range.

// Make sure that the alpha argument contains an integer value between 0 and 255
public void setAlpha(@IntRange(from=0,to=255) int alpha) {... }// Make sure the alpha argument contains floating point values between 0.0 and 1.0
public void setAlpha(@ FloatRange (from = 0.0, the to = 1.0) float alpha) {... }Copy the code

The @size annotation checks the Size of collections or arrays, as well as the length of strings. The @size annotation can be used to verify the following features:

  • Minimum size (e.g@Size(min=2))
  • Maximum size (e.g@Size(max=2))
  • Exact size (e.g@Size(2))
  • The size must be a multiple of the specified number (e.g@Size(multiple=2))

For example, @size (min=1) checks to see if a collection is not empty, and @size (3) verifies that an array contains exactly three values.

// Make sure the Location array contains at least one element
void getLocation(View button, @Size(min=1) int[] location) {
    button.getLocationOnScreen(location);
}
Copy the code

Permissions annotations

The @requiresperMission annotation validates the permissions of the method caller. To check for the existence of a permission in the list of valid permissions, use the anyOf attribute. To check if you have a set of permissions, use the allOf attribute.

// to ensure that the setWallpaper() method caller has permission-set_wallpapers permission
@RequiresPermission(Manifest.permission.SET_WALLPAPER)
public abstract void setWallpaper(Bitmap bitmap) throws IOException;
Copy the code
// The caller of the copyImageFile() method is required to have read permission to the external storage space and to read permission to the location metadata in the copied image
@RequiresPermission(allOf = { Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.ACCESS_MEDIA_LOCATION})
public static final void copyImageFile(String dest, String source) {
    / /...
}

Copy the code

For intent permissions, add permission requirements to the string field that defines the intent action name:

@RequiresPermission(android.Manifest.permission.BLUETOOTH)
public static final String ACTION_REQUEST_DISCOVERABLE =
            "android.bluetooth.adapter.action.REQUEST_DISCOVERABLE";
Copy the code

If you need separate Read and Write access to the content provider, you need to encapsulate each permission requirement in the @requiresperMission.read or @requiresperMission.write annotation:

@RequiresPermission.Read(@RequiresPermission(READ_HISTORY_BOOKMARKS))
@RequiresPermission.Write(@RequiresPermission(WRITE_HISTORY_BOOKMARKS))
public static final Uri BOOKMARKS_URI = Uri.parse("content://browser/bookmarks");
Copy the code

Return value annotation

Use the @checkResult annotation to check that the return value of a method is being processed and that the result or return value of the method is actually being used.

This might be a bit tricky to understand, but here’s an example from Java String.trim() :

String str = new String(" www.ocnyang.com ");
// Delete the header and tail whitespace
System.out.println("Website:" + str.trim() + "。");// Print results: website: www.ocnyang.com.
System.out.println("Website:" + str + "。");// Print results: website: www.ocnyang.com.
Copy the code

The following example adds annotations to the checkPermissions() method to ensure that the return value of the method is actually referenced. In addition, this will specify the enforcePermission() method as the alternative method to be recommended to the developer:

@CheckResult(suggest="#enforcePermission(String,int,int,String)")
public abstract int checkPermission(@NonNull String permission, int pid, int uid);
Copy the code

CallSuper annotations

The @callsuper annotation is mainly used to emphasize that when overriding a superclass method, the super.xxx() method should be called when implementing the superclass method. When using @callsuper to modify a method, an error will be reported if the subclass overwrites the superclass method and does not implement the call to the superclass method.

Keep notes

Using the @keep annotation ensures that classes or methods with this annotation are not removed during build obfuscation to reduce code size. This annotation is often added to methods and classes accessed through reflection to prevent the compiler from treating the code as unused.

Note: Classes and methods annotated with @Keep are always included in your application’s APK, even if you never reference them in your application logic.

Code exposure scope annotations (Understand)

You can use the @VisibleForTesting annotation to make invisible classes, functions, or variables visible when accessing them in a unit test.

Typedef annotations

Enumeration Enum is a complete class in Java. Each value in an enumeration is an object in an enumeration class. So the enumerated values we use will consume more memory than integer constants. We are better off using constants instead of enumerations. But you can’t limit values by using constants instead. The above two notes are intended to solve this problem.

The @Intdef and @stringdef annotations are magic variable annotations provided by Android that allow you to create enumerations of integer sets and string sets to proxy Java enumeration classes. It will help us with the ability to select variables like Enum at compile time. @intdef and typedef are very similar in that you can create another annotation and specify a list of the values you want for integer constants with @intdef, and then you can use that defined annotation to modify your API. So let’s replace Enum with @intdef.

public class MainActivity extends Activity {
    public static final int SUNDAY = 0;
    public static final int MONDAY = 1; {... Ellipsis}@IntDef({SUNDAY, MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY})
    @Retention(RetentionPolicy.SOURCE)
    public @interface WeekDays {
    }

    @WeekDays
    int currentDay = SUNDAY;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        setCurrentDay(WEDNESDAY);

        @WeekDays int today = getCurrentDay();
        switch (today) {
            case SUNDAY:
                break;
            case MONDAY:
                break; {... Ellipsis}default:
                break; }}/** * the argument can only be passed as an integer in the declared scope, otherwise the compiler will not pass *@param currentDay
     */
    public void setCurrentDay(@WeekDays int currentDay) {
        this.currentDay = currentDay;
    }

    @WeekDays
    public int getCurrentDay(a) {
        returncurrentDay; }}Copy the code

Description:

  1. Declare some necessary int constants
  2. Declare an annotation as WeekDays
  3. use@IntDefDecorates WeekDays, set to a collection to be enumerated
  4. use@Retention(RetentionPolicy.SOURCE)Specifies that annotations exist only in the source code and are not added to the class file

Only the specified type can be passed in the call. If the type is not correct, the compilation fails.

We can also specify integer values as flag bits, that is, these integer values can be amand with ‘|’ or ‘&’. If we define the annotation in the above code as the following flag bit:

@IntDef(flag = true, value = {SUNDAY, MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY})
public @interface Flavour {
}
Copy the code

Then you can call:

setCurrentDay(SUNDAY & WEDNESDAY);
Copy the code

@ StringDef similarly.

Custom annotations

Java yuan notes

The name describe
@Retention Identify how this annotation is stored, whether it is only in code, marshaled into a class file, or accessible at run time via reflection
@Documented Marks whether these annotations are included in the user document, that is, included in Javadoc
@Target Mark the target of the annotation
@Inherited Marks which annotation class the annotation inherits from
@Repeatable Java 8 began to support the idea that an annotation can be used more than once on the same declaration

@Retention Length of annotation Retention. Optional parameter value in the enumeration type Java lang. The annotation. RetentionPolicy, values are:

  • Retentionpolicy. SOURCE: Annotations are reserved only at the SOURCE stage. They are discarded and ignored by the compiler during compilation and are not written to the class file.
  • Retentionpolicy. CLASS: Annotations are only reserved until compile time and are written to the CLASS file, which is not loaded into the JVM;
  • Retentionpolicy.runtime: Annotations can be retained until the application is run, and they are loaded into the JVM, so they can be retrieved by reflection while the application is running.

@target is used to indicate to whom the modified annotation ends up being targeted, i.e., is your annotation intended to modify a method? Modify class? Also used to modify field properties. The possible values in the enumeration class Java. Lang. The annotation. ElementType, including:

  • Elementtype. TYPE: allows modified annotations to be applied to classes, interfaces, and enumerations;
  • Elementtype. FIELD: allows action on attribute fields;
  • ElementType.METHOD: allows actions on methods;
  • Elementtype. PARAMETER: allows action on method parameters;
  • Elementtype. CONSTRUCTOR: Allows action on a CONSTRUCTOR;
  • Elementtype. LOCAL_VARIABLE: allowed on local local variables;
  • Elementtype. ANNOTATION_TYPE: allows annotation;
  • Elementtype. PACKAGE: Allows action on packages.

The @target annotation can also accept an array of parameters that can be applied to multiple Target types, such as @target ({elementtype. FIELD, elementtype.local_variable}).

Custom annotations

You can customize your own annotations as needed, and then add custom annotations where necessary. Note that whenever a custom annotation is defined, there must be a corresponding process for handling the custom annotation, otherwise it is not practical. The main function of annotation is the annotation processing method. Annotation processing is generally divided into two kinds:

  • The annotation information is reserved to runtime, when the annotation information of the class, method, and field is retrieved through reflection operations, and then processed accordingly
  • Reserved until compile time, this is usually done by using the APT annotation interpreter to automatically generate code from annotations. To put it simply, APT can help us generate code and generate class files according to rules. Open source libraries such as ButterKnife, Dagger, EventBus, etc. are implemented using annotations.

Because custom annotations involve more content. I won’t cover custom annotations in detail in this installment, but I’ll cover them in a separate article later.

Attached reference article

  • Improve code review with annotations
  • Use the Support Annotations to optimize code in Android
  • Java annotations