Reprint please indicate the source: juejin.cn/post/684490… This article is from: Tour home page

preface

Since version 19.1, the Android Support Library has introduced a new annotation Library, which contains many meta-annotations. Using them to modify our code allows us to improve our application development efficiency and catch problems earlier. And standardize code to make it more readable. This article will take a brief look at these annotations and their use. If there are any errors or omissions, please leave a message or add ~

Note: Our new project now relies directly on the support-appCompat package, which already relies on the Annotations package. If your project reported an error with the following comments, you can add a comment pack:

dependencies {
    compile 'com. Android. Support: support - annotations: 22.2.0'
}Copy the code

@IntDef & @StringDef

Annotations that replace enumerations in Java, such as @intdef, are defined and used as follows:

@IntDef({RED, BLUE, YELLOW})
@Retention(RetentionPolicy.SOURCE)
public @interface LightColors{};

public static final int RED = 1;
public static final int BLUE = 2;
public static final int YELLOW = 3;

public void setColor(@LightColors int color){
}Copy the code
  • @interface: Declares the new enumerated annotation type.
  • @Retention(retentionPolicy.source) : Tells the compiler not to store enumerated annotation data in a.class file.

If you allow constants and signs (for example: |, &, ^, etc.), the combination of, we can use flag properties, such as:

@IntDef(flag = true, value = {RED, BLUE, YELLOW})Copy the code

Use:

setColor(RED | BLUE);Copy the code

@Nullable & @NonNull

  • @nullable: Annotated elements can be null.
  • @nonNULL: Annotated elements cannot be considered null.

The comments above can modify the following elements: 1, method parameters. Such as:

@Nullable
private String data;Copy the code

2. The return value of the method. Such as:

@Nullable
public String getData() {return data;
}Copy the code

3. Member attributes. Such as:

public void setData(@Nullable String data){
}Copy the code

If an empty argument is passed to a method whose @nonnull method argument is modified, the following warning will be raised:

passing "null" argument to parameter annotated as @NotNullCopy the code

@FloatRange & @IntRange

@floatRange and @intrange are annotations for scoping. Where @floatrange qualifies float and @intrange qualifies int. Like the annotations above, they can modify method parameters, method return values, and member attributes.

Taking @intrange as an example, the parameters of the modification method are defined as follows:

public void setAge(@IntRange(from = 1, to = 180) int age){
}Copy the code

If the parameter is not in the range of 1-180, such as setAge(0), the compiler will report the following error:

Value must be ≥ 1 and ≤ 180 (was 0)Copy the code

@Size

The @size annotation is used to define the length of the method. Like the previous annotation, you can modify method parameters, method return values, and member attributes.

  • Limit the length of a string:
    public void setData(@Size(4) String data){
    }Copy the code

    If the string length passed in is not equal to 4, the compiler will directly report an error:

    Length must be exactly 4Copy the code
  • Limit the length of an array:
    public void setData(@Size(4) int[] data){
    }Copy the code
  • A special qualification, such as a multiple of 2:
    public void setData(@Size(multiple = 2) int[] data){
    }Copy the code

    Define the minimum length:

    @Size(min = 2)Copy the code

    Limit the maximum length:

    @Size(max = 2)Copy the code

    Is equivalent to@Size(2)Writing:

    @Size(value = 2)Copy the code

@RequiresPermission

The purpose of this annotation is to indicate that what the method does requires permissions. If a single permission is required:

@RequiresPermission(Manifest.permission.CALL_PHONE)
private void callPhone(String phone){
}Copy the code

A set of permissions is required:

@RequiresPermission(allOf = {
        Manifest.permission.READ_EXTERNAL_STORAGE,
        Manifest.permission.WRITE_EXTERNAL_STORAGE})
public static final void copyFile(String dest, String source) {... }Copy the code

For intent permissions, we can define the intent action name as a string:


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

For permissions for content providers that require separate Read and Write permissions, we can include 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

If permissions depend on a specific value supplied to a method parameter, you can use @requiresperMission on the parameter itself without listing the specific permissions, as in the startActivity(Intent) method:

public abstract void startActivity(@RequiresPermission Intent intent, @Nullable Bundle) {... }Copy the code

When we use this approach (indirect permissions), the build tool performs a data flow analysis to check whether the parameters passed to the method have any @REQUIresperMission annotations. Such as:

Intent intent = new Intent(Intent.ACTION_CALL);
intent.setData(Uri.parse("tel:1234567890"));
startActivity(intent);Copy the code

StartActivity (intent) ¶

call requires permission which may be rejected by user: code should explicitly check to see if permission is available (with `checkPermission`) or explicitly handle a potential `SecurityException`Copy the code

Because intent.action_call is marked with permission annotations:

@SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
@RequiresPermission(Manifest.permission.CALL_PHONE)
public static final String ACTION_CALL = "android.intent.action.CALL";Copy the code

@CheckResult

The @checkResult annotation is applied to a method to verify that a return value is being processed. An error is reported if no return value is processed.

@CheckResult
public String getData(String data) {
    return data.trim();
}Copy the code

Thread annotations

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

  • @mainthread: methods that indicate tags should only be called on the MainThread. If you mark a class, all methods in that class should be called on the main thread. Example :(typically, the main thread of an application is also the Ui thread. However, in special cases, the main thread of an application may not be its Ui thread.)

    @MainThread
    public void deliverResult(D data) { ... }Copy the code
  • @uithRead: Methods or constructors that represent tags should only be called on the Ui thread. If you mark a class, all methods in that class should be invoked on the Ui thread. Ex. :

    @UiThread
    public abstract void setText(@NonNull String text) {... }Copy the code
  • @workerThread: Methods that represent tokens should only be called on worker threads. If you mark a class, all methods in that class should be invoked on a worker thread. Ex. :

    @WorkerThread
    protected abstract FilterResults performFiltering(CharSequence constraint);Copy the code
  • @binderThread: The method that indicates the tag should only be called on the bound thread. If you mark a class, all methods in that class should be called on the binding thread. Ex. :

    @BinderThread
    public BeamShareData createBeamShareData() {... }Copy the code
  • AnyThread: indicates that tagged methods can be called from AnyThread. If you mark a class, all the methods in that class can be called from any thread. Ex. :

    @AnyThread
    public void deliverResult(D data) { ... }Copy the code

The build tool treats the @MainThread and @UithRead annotations as interchangeable, so we can call the @UithRead method from the @MainThread method and vice versa. However, if the system is applied with multiple attempts on different threads, the Ui thread can be different from the main thread. Therefore, we should use the @UithRead annotation for application view hierarchy associations and the @MainThread annotation only for application lifecycle associations.

Resource annotation

In Android, almost all resources have their corresponding IDS. When we use them, we can use them directly, such as:

textView.setText(getResources().getText(R.string.app_name));Copy the code

However, there is a risk that if you do not write the specified resource annotation, for example, if you pass a random 0, the corresponding resource will not be found. To avoid errors caused by our own carelessness, we can use resource annotations, such as:

public int getText(@StringRes int id){
}Copy the code

So when we call this method, if we pass a resource ID that is not a String, the compiler will give us an error.

In addition to the @stringres resource annotations, there are:

  • @integerres: r.integer Type resource.
  • AnimatorRes: r.nimator resource.
  • AnimRes: r.nim-type resource.
  • @arrayres: resources of the r.ray type.
  • @attrres: r.atr type resource.
  • @boolres: R.pool type resources.
  • @colorres: r.color type resource.
  • @dimenres: R.dimenen type resource.
  • DrawableRes: indicates an R. rawable resource.
  • @fractionRes: r.frAction Resource. (percentage)
  • @idres: r.ID resource.
  • @interpolatorres: R.interpolator type resource. (Interpolator)
  • @layoutres: r.layout type resource.
  • @menures: r.Menu type resource.
  • @Pluralsres: R.plurals type resource. (plural)
  • @rawres: R.raw-type resources.
  • @styleableres: r.styleable resource.
  • StyleRes: r.style type resource.
  • @transitionRes: r.configuration Type resource.
  • XmlRes: r.xML type resource.
  • AnyRes: Unknown source. (Indicates that you do not know what type of resource it is. For example, it could be R.Delaware or R.Tring.)

@ColorInt

The @colorint annotation defines the color value. (ARGB: 0xAARRGGBB)

public void setColor(@ColorInt int color) {

}Copy the code

If you use the resource ID directly, an error is reported as follows:

setColor (R.c olor. ColorAccent) / / an errorCopy the code

The correct usage is:

setColor(0xFFFF00FF);Copy the code

To use a resource ID, use the contextCompat.getColor () method:

setColor(ContextCompat.getColor(context, R.color.colorAccent));Copy the code

@CallSuper

This annotation is used to modify the method, indicating that the super method must be called when the method is overridden. Such as onCreate() method:

@CallSuper
protected void onCreate(Bundle savedInstanceState) {
}Copy the code

To override the onCreate() method, you must call the super method:

super.onCreate(savedInstanceState);Copy the code

Otherwise, an error is reported.

@VisibleForTesting & @Keep

Use @VisibleFortesting and @keep annotations to indicate the accessibility of a method, class, or field.

  • @visibleFortesting: This annotation serves only as a comment to tell other developers why the marked code is so visible (for testing purposes). Therefore, it is often used to refer to public or protected. Referring to private is not an error, but it does not make sense.
  • @keep: The specified code of the tag will not be obfuscated when obfuscated.

Reference:

  • Developer.android.com/studio/writ…
  • Droidyue.com/blog/2016/0…