Using Annotation

Foreword

Annotation(注解)是从Java 1.5开始新加的特性,距今已经好多年的历史了。不得不说注解是一个很好用的东西。不过本文不打算深入解释Annotation,而是准备从Android提供的Annotation来讲述其使用技巧。

Why Annotation

在开发过程中,我们会遇到各种设计接口、方法时,需要对方法的参数进行限制,来避免或者尽量避免由于开发人员的错误调用而导致程序运行不正常乃至崩溃。 例如:我们常用的TextViewsetText方法有多个重载实现,而我们常用的为:

public final void setText(CharSequence text) {
    setText(text, mBufferType);
}

public final void setText(int resid) {
    setText(getContext().getResources().getText(resid));
}

这两个方法。当我们从网络流(或者其他一些场景下)获取到数据,直接调用setText方法,经常会出现传入错误的int类型值,这个int类型值并不是正确的R.string.*值,在程序运行的时候就会报错,导致程序崩溃(Force close)。

在没有注解的情况下,我们是很难做出判断,这些操作只能凭开发人员的细心判断达到。但是人往往是会犯错的,尤其是多人协作的时候,这种问题尤其容易出现。而在Annotation的帮助下,我们可以很好的实现控制,让编译器去协助我们完成检查,在编译时便检查出错误。

注意:这个错误只能在视觉上呈现,实际编译仍能通过。

How to use Annotation

针对上述场景,Android的support-annotation包里提供了StringRes这个Annotation,在设置了@StringRes注解的参数PARAMETER, 使用非R.string.*类型的int值是,便会报错: Error

注:本文的IDE为Android Studio, 并未测试Eclipse上的显示和提示.

查看StringRes的源码实现如下:

/**
 * Denotes that an integer parameter, field or method return value is expected
 * to be a String resource reference (e.g. {@link android.R.string#ok}).
 */
@Documented
@Retention(SOURCE)
@Target({METHOD, PARAMETER, FIELD})
public @interface StringRes {
}

我们查看TextView的对应方法代码看到如下情况: Hint

我们注意到并没有在方法的参数里标记@StringRes,只是在左边有一个@标识,鼠标悬停后有上图的显示其使用了外部的Annotation,具体的情况目前并未深入分析,此处挖个坑。

注意: Android提供了android.support.annotation.StringResandroid.annotation.StringRes, 后者是@hide的,也就是说只能在系统app中使用。

How to use Annotation

说了这么多,是时候该操刀上了。使用起来很简单:

private void testStringRes(@StringRes int id) {
    ...
}

然后在使用的时候直接调用该方法,如果有不符合的参数传入,编译器便会给出错误提示。 Use

More Annotations

除了上述提到的StringRes这个Annotation外,android.support.annotation包下还有其余24个annotation,主要分为一下几类:

  • 1:和StringRes一样的*Res注解;
  • 2:NonNullNullable;
  • 3:IntDefStringDef;

NonNullNullable相对比较简单,也是和上述的StringRes一样使用,不过区别是这两者在IDE中是以Warning(警告)形式出现,而StringRes是以Error(错误)形式出现。

注意: 上述的Error并不是真正意义上的Error,只是在IDE中会显示红色标记,而Warning只会显示一个不显眼的背景高亮。 而且在编译的时候都能通过编译并运行。

Warning

IntDefStringDef允许我们自定义新的注解类型,从而达到实现参数类型控制的目的,其达到的效果和枚举Enum类似。 具体可参考android.app.ActionBar类的相关实现:

@Retention(RetentionPolicy.SOURCE)
@IntDef({NAVIGATION_MODE_STANDARD, NAVIGATION_MODE_LIST, NAVIGATION_MODE_TABS})
public @interface NavigationMode {}


/**
 * Set the current navigation mode.
 *
 * @param mode The new mode to set.
 * @see #NAVIGATION_MODE_STANDARD
 * @see #NAVIGATION_MODE_LIST
 * @see #NAVIGATION_MODE_TABS
 *
 * @deprecated Action bar navigation modes are deprecated and not supported by inline
 * toolbar action bars. Consider using other
 * <a href="http://developer.android.com/design/patterns/navigation.html">common
 * navigation patterns</a> instead.
 */
public abstract void setNavigationMode(@NavigationMode int mode);

其他

关于Annotation的实现原理以及自定义Annotation,留待下次讲解吧。

blog comments powered by Disqus