Skip to content

Latest commit

 

History

History
260 lines (193 loc) · 7.24 KB

0001-support-annotations.asc

File metadata and controls

260 lines (193 loc) · 7.24 KB

Android Support Annotations库介绍

📎
反馈与建议,请移步: #2

文章更新历史:

  • 2015/01/29 文章发布

  • 2015/07/26 更新文章,解读新增的annotations


从Android Support Library v19.1开始,Support库新增了一个annotations子库。 这个库里面定义了一些annotation,可以被用于在代码中强制添加一些调用约束, 进而便于IDE对代码进行静态检查,以发现潜在的问题。

关于该库的官方介绍和用法,请看 这里这里

本文简单总结一下其用法。

1. 引入Annotations库

直接修改build.gradle配置文件,添加该库的引用。例如:

dependencies {
    compile 'com.android.support:support-annotations:22.2.0'
}

也可以通过Android Studio的Project Structure (File → Project Structure,Dependencies)添加引用。

📎
Annotations库并没有被上传到jcenter(其它Support库也是), 而是存放于Android SDK中的一个本地maven库中。 因此,如果需要在Java模块中使用Annotations库,则需要添加Support库的maven库: maven { url '<your-SDK-path>/extras/android/m2repository' }

2. annotations介绍

2.1. null相关

用于修饰Method的参数和返回值,以便IDE对相关的约束进行检查。列举如下:

  • @Nullable 表示允许为null

  • @NonNull 表示不允许为null

从官网抄一段例子:

import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
...

    @Nullable
    @Override
    public View onCreateView(String name, @NonNull Context context, @NonNull AttributeSet attrs) {
        ...

需要注意的是,对于一个变量或者返回值,除了可指定@NonNull和@Nullable之外, 还有第三种状态,即“未指定”。

⚠️
当一个方法可能会返回null时,我们有两种选择: 一是指定@Nullable,二是什么都不指定。 如果打算指定为@Nullable,这意味着所有调用者都需要检查返回值是否为null。 也许,这并不是期望的行为,可能更好的选择是什么都不指定。

2.2. 资源类型相关

用于修饰对资源ID的相关引用,以便IDE对相关的资源类型进行检查。列举如下:

  • @AnimRes

  • @AnimatorRes

  • @AnyRes

  • @ArrayRes

  • @AttrRes

  • @BoolRes

  • @ColorRes

  • @DimenRes

  • @DrawableRes

  • @FractionRes

  • @IdRes

  • @IntegerRes

  • @InterpolatorRes

  • @LayoutRes

  • @MenuRes

  • @PluralsRes

  • @RawRes

  • @StringRes

  • @StyleRes

  • @StyleableRes

  • @XmlRes

从官网抄一段例子:

import android.support.annotation.StringRes;
...
    public abstract void setTitle(@StringRes int resId);

2.3. 常量定义相关

2.3.1. @IntDef

我们经常使用int来定义一些常量来代替使用enum,可以使用这个annotation来添加相关的约束。

还是搬官网的例子:

import android.support.annotation.IntDef;
...
public abstract class ActionBar {
    ...
    @Retention(RetentionPolicy.SOURCE)
    @IntDef({NAVIGATION_MODE_STANDARD, NAVIGATION_MODE_LIST, NAVIGATION_MODE_TABS})
    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;

    @NavigationMode
    public abstract int getNavigationMode();

    public abstract void setNavigationMode(@NavigationMode int mode);

再搬一个例子,关于flags类型(可进行异或运算)的常量定义:

    @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 {}

2.3.2. @StringDef

该annotation用于修饰字符串常量,用法跟前面的@IntDef类似。

2.4. 线程相关

从Support库v22.2开始,加入了几个线程相关的annotations:

  • @MainThread 指定在主线程中执行

  • @UiThread 指定在UI线程中执行

  • @WorkerThread 指定在非UI线程中执行

  • @BinderThread 指定在Binder线程中执行

如果某个方法仅在某一类线程中调用,那么可以为其添加上面的annotation; 如果某个类的所有方法都仅在某一类线程中调用,那么可以为类添加线程annotation。

2.4.1. @MainThread vs @UiThread

一个进程中,仅有一个主线程。 @MainThread就是指这个主线程,同时这个主线程也是@UiThread。

理论上,在一个进程中,可以有多个@UiThread,虽然很少见。

在实际使用中,可以遵循如下原则:

  • 生命周期相关的使用@MainThread(例如,AsyncTask#onProgressUpdate方法)

  • View体系使用@UiThread

Android Studio、Android Lint等工具会把两者认为是可互换的, 因此不会区分两者。

2.5. 接受ARGB颜色值

如果一个方法的参数接受颜色资源ID,则可以使用前面的@ColorRes; 如果接受颜色的ARGB值,则可以使用@ColorInt。

2.6. 限定参数值范围

2.6.1. @FloatRange

对于float或double类型的参数,可以使用@FloatRange来指定取值范围:

public void setAlpha(@FloatRange(from=0.0, to=1.0) float alpha) {

2.6.2. @IntRange

对于int或long类型的参数,可以使用@IntRange来指定取值范围。

public void setAlpha(@IntRange(from=0,to=255) int alpha) {

2.6.3. @Size

如果对数组、集合或者String的元素个数有所约束,则可以使用@Size:

  • @Size(min=N) 指定元素最小个数为N

  • @Size(max=N) 指定元素最大个数为N

  • @Size(N) 精确指定元素个数为N

  • @Size(multiple=N) 指定元素个数为N的倍数

2.7. 指定权限

可以通过@RequiresPermission来指定调用者需要拥有的权限, 一般只有系统代码中才会用得到。

2.8. 强制调用基类方法

如果允许一个方法被重写,但要求在子类的重写方法中调用基类的方法, 则可以使用@CallSuper:

@CallSuper
protected void onCreate(@Nullable Bundle savedInstanceState) {

2.9. 强制使用返回值

@CheckResult 适用于必须使用返回值的场景。例如:

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

2.10. 测试可见

当仅为了测试,把类、方法或者字段的可见性放大时,可用@VisibleForTesting来修饰。

2.11. 混淆保留

同ProGuard的“-keep”,用于在代码混淆时阻止某些代码被混淆。

⚠️
此功能还在开发中,目前不可用。

3. 结语

在项目中支持这些annotation是比较繁琐的,就像为项目添加单元测试的支持一样。 但同样的,如果能够在项目中支持这些annotation,其带来的质量提升是很明显的。 特别是对于library project项目,建议在代码规范予以支持。