使用 Support Annotation Library
写在前面
在看《Android高级进阶》一书看到注解那一章,发现看似不起眼的@后面其实隐藏的大学问。
注解,相信我们程序猿不可能陌生,android有一个在api 19.1 上引入了一个全新的函数包里面全是我们熟悉又陌生的注解。熟练的使用这东西可以把你的代码可读性提高数倍。
注解的分类
support-annotation-23.1.1函数包中,一共有39种注解,可以分为11类来跟大家说明一下。
Nullness注解
很明显是表示能不能为空的注解,一般会用在参数或者返回值上,这种注解有:
@Nullable //标记可以为空
@NonNull //标记不能为空
如果有违反注解标记的代码的时候,Android Studio会给出提示,警告。
资源类型注解
Android的资源通常是以整型值来表示是常识,并且会保存在R.java文件当中。然而会有一个问题,在编译的过程中如果我要一个R.layout.***的整型资源参数,我传入了一个String资源值也不会报错,直到我运行程序才会出现问题,报错。
所以为了防止这种这么降低效率的情况出现,我们很有必要需要资源注解来声明我们到底需要的是什么资源。
注解 | 作用 |
---|---|
AnimationRes | 标记整型值是 android.R.animator 类型 |
AnimRes | 标记整型值是 android.R.anim 类型 |
AnyRes | 标记为整型值是任意资源 |
ArrayRes | 标记整型值是android.R.array类型 |
AttrRes | 标记整型值是android.R.attr类型 |
BoolRes | 标记整型值是布尔类型 |
ColorRes | 标记整型值是android.R.color类型 |
DrawableRes | 标记整型值是android.R.drawable类型 |
FractionRes | 一般在动画xml文件中使用,如:50%p 表示占parent 50% |
IdRes | 标记整型值是anroid.R.id类型 |
IntegerRes | 标记整型值是anroid.R.integer类型 |
InterpolatorRes | 标记整型值是android.R.interpolator类型 |
LayoutRes | 标记整型值是android.R.layout类型 |
MenuRes | 标记整型值是android.R.menu类型 |
PluralsRes | 标记整型值是android.R.plurals类型 |
RawRes | 标记整型值是android.R.raw类型 |
StringRes | 标记整型值是android.R.string类型 |
StyleableRes | 标记整型值是android.R.styleable类型 |
StyleRes | 标记整型值是android.R.style类型 |
TransitionRes | 标记整型值是android.R.transition类型 |
XmlRes | 标记整型值是android.R.xml类型 |
所有资源注解都一样情况,如果输入的资源参数跟注解的相违反,那么Android Studio就会检查出来然后报错。
类型定义注解
使用这一类注解我们可以创建一个自己的新注解,并可以使用这个新注解来标记自己的API,比如@IntDef
的用法,我们可以看看ActionBar里面是怎么用它的
import android.support.annotation.InDef;
...
public abstract class ActionBar{
//跟编译器声明不需要在.class文件中存储注解数据
@Retention(RetentionPolicy.SOURCE)
//定义可以接受的常量列表
@IntDef({NAVIGATION_MODE_STANDARD,NAVIGATION_MODE_LIST,NAVIGATION_MODE_TABS})
//定义NagavitionMode 注解
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;
//使用NagavitionMode注解
@NavigationMode
...
public abstract void setNagavitionMode(@NagavitionMode int mode);
}
在使用setNagavitionMode这个方法的时候,我们传的参数mode要是不是定义的三个常量之一时,Android Studio就会发出警告。
一般使用这类注解,我们会把它当作枚举的代替品,而且它比枚举更加的易懂,方便。
线程注解
线程注解有四种 :
- @UiThread:标记运行在UI线程。
- @MainThread:基本同UiThread的用法一样,不过一般MianThread会注解生命周期相关函数。
- @WorkThread:标记运行在后台的线程。
- @BinderThread:标记运行在Binder的线程。
以AsyncTask的实现为例子:
@MainTread
protected void onPreExecute(){}
@WorkerThread
protected adstract Result doInBackground(Params...params);
@MainThread
protected void onProgressUpdate(Progress...values){};
RGB颜色值的注解
这个跟 @ColorRes
不太一样,@ColorInt
标记的是一个代表颜色的RGB值,用法例如TextView源码里面:
public void setTextColor(@ColorInt int color){
...
}
值范围注解
标记参数的取值范围,防止传入错误的参数。声明范围的注解有三种:
-
@Size
:主要声明的对象是数组,集合,字符串等参数,用来声明它们的长度范围,用法如下:
@Size(min =1) //可以表是集合不能为空
@Size(max = 23) //可以表示字符串最大字符个数是23
@Size(2) //可以表示数组的元素为2个
@Size(multiple = 2) //可以表示数组大小为2的倍数
-
@IntRange
:主要声明对象是int跟long,用法如下:
public void setAlpha(@IntRange(from = 0 ,to = 255) int alpha){...}
-
@FloatRange
:主要声明对象是float或者double,用法如下:
public void setAlpha(@FloatRange(from = 0.0,to =1.0)){...}
权限注解
android 的权限管理一直是令人又爱又恨的东西,我们需要在AndroidManifest.Xml文件里面声明权限,不然我们无法使用该权限去运行某些功能,为了能在编译的时候就能及时发现缺失的权限,我们可以使用@RequiresPermission注解。
- 如果函数调用需要声明一个权限,语句如下:
@RequiresPermission(Manifest.permission.SET_WALLPAPER)
public abstract void setWallpaper(Bitmap bitmap)throws IOException;
- 如果函数调用需要声明集合中至少一个权限,语句如下:
@RequiresPermission(anyOf = {Mainfest.permission.ACCESS_COARSE_LOCATION,Mainfest.permission.ACCESS_FINE_LOCATION})
public abstract Location getLastKnownLocation(String provider);
- 如果函数调用需要声明多个权限,语句如下:
@RequiresPermission(allOf = {Mainfest.permission.ACCESS_COARSE_LOCATION,Mainfest.permission.ACCESS_FINE_LOCATION})
public abstract Location getLastKnownLocation(String provider);
- 对于Intent调用所需权限,可以在Intent的ACTION字符串定义处添加注解,语句如下:
@RequiresPermission(android.Mainfest.permission.BLUETOOTH)
public static final String ACTION_REQEST_DISCOVERABLE ="android.bluetooth.adapter.action.REQUEST_DISCOVERABLE";
- 对于ContentProvider相关所需的权限,可能同时需要读和写这两个操作,对应不同的权限声明,语句如下。
@RequiresPermission.Read(@RequiresPermission(READ_HISTORY_BOOKMARKS))
@RequiresPermission.Write(@RequiresPermission(WRITE_HISTORY_BOOKMARKS))
public static final Uri BOOKMARKS_URI = Uri.parse("content://browser/bookmarks");
重写函数注解
@CallSuper
这是一个用在可能需要被重写的方法上的,提示开发者重写该方法需要回调父类的同一方法。示例如下:
@CallSuper
protected void onCreate(@Nullable Bundle savedInstanceState);
注解返回值
在编写函数的时候我们需要调用者对函数的返回值进行处理,那么可以用@CheckResult注解来提示开发者。Android源码的Context类为例:
@CheckResult(suggest="#enforcePermission(String,int,int,String)")
@PackageManager.PermissionResult
public abstract int checkPermission(@NonNull String permission,int pid,int uid);
如果调用者没有检查返回值,Android Studio 会给出警告,内容为suggest里面的内容。
测试可见注解
测试的过程中我们会访问一些不可见的类,变量还有函数,使用@VisibleForTesting可以让它们变得测试可见。
标记非混淆注解
@Keep
用来注解代码混淆过程中不需要混淆的部分。使用方法:
public class AnnotationDemo{
@Keep
public void doSomething(){
//....
}
//...
}
注解的去向
如果项目打包成aar压缩包,注解信息会被抽离出来放在aar文件的annotation.zip中。
写在后面
以上是对Support Annotation Library的一些知识总结,希望大家有所收获。
讲道理,这么多种类的注解,要是灵活的运用在团队的项目开发中,妈妈再也不用担心别人读不懂我的代码了。