使用Lint 和 Annotations来提升代码质量

2016-08-18  本文已影响383人  ShenJC

使用 Lint 来检查代码

在 Android Studio 中使用 lint

在Android Studio中,当你build app的时候,Lint和IDE 检查会自动运行。

使用 File > Settings > Editor > Inspections 菜单可以打开检查配置界面

使用Android Studio,可以在build.gradle文件中添加 lintOptions 属性 可以对Lint 的检查做相关的设置。下面是示例代码:

android {
    lintOptions {
       // set to true to turn off analysis progress reporting by lint
       quiet true
       // if true, stop the gradle build if errors are found
       abortOnError false
       // if true, only report errors
       ignoreWarnings true
       }
       ...
    }

在指定目录上右击,在右击菜单中选择Analyze > Inspect Code 就可以进行手动的Lint代码检查。

在命令行中跑 lint

检查工程目录下的所有文件:

lint [flags] <project directory>

使用下面命令可以扫描myproject 目录下的所有文件以及子文件。参数MissingPrefix 表示只扫描缺少Android 命名前缀的XML属性。

lint --check MissingPrefix myproject 

通过命令来查看使用方法和参数:

lint --help

配置lint

在Android Studio中配置lint

有两种方法可以看到Lint的warnings和errors 结果:

设置默认的Lint 检查:

  1. 打开项目,选择 File > Other Settings > Default Settings,选择 Editor > Inspections.
  2. 在Profile 选项中,选择 Default or Project Default来选择是全局作用域还是project作用域。
  3. 在窗口中进行设置。

配置手动执行的Lint检查:

  1. 打开项目,选择你要测试的目录。使用Analyze > Inspect Code.
  2. 在指定检查范围弹出框中,选择检查scope和profile。scope指定哪些文件你想要分析,profile指定你想要执行的Lint checks。

使用配置文件lint.xml

可以使用lint.xml来指定Lint的检查属性。手动创建这个文件的话,把它放到project的根目录下。 如果你是通过Android Studio来配置检查属性,lint.xml会自动创建在project根目录下。

lint.xml结构如下,由<lint> 父tag包含一个或多个<issue> 子元素组成,每个<issue> 指定一个唯一的由Lint定义过的id属性。

<?xml version="1.0" encoding="UTF-8"?>
<lint>
    <!-- Disable the given check in this project -->
    <issue id="IconMissingDensityFolder" severity="ignore" />

    <!-- Ignore the ObsoleteLayoutParam issue in the specified files -->
    <issue id="ObsoleteLayoutParam">
        <ignore path="res/layout/activation.xml" />
        <ignore path="res/layout-xlarge/activation.xml" />
    </issue>

    <!-- Ignore the UselessLeaf issue in the specified file -->
    <issue id="UselessLeaf">
        <ignore path="res/layout/main.xml" />
    </issue>

    <!-- Change the severity of hardcoded strings to "error" -->
    <issue id="HardcodedText" severity="error" />
</lint>

在Java和XML源文件中配置lint 检查

可以在java和XML源文件中禁用Lint检查.

关闭"NewApi"问题的检查
@SuppressLint("NewApi") @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main);
关闭"ParserError"的问题检查
@SuppressLint("ParserError") public class FeedProvider extends ContentProvider {
关闭Java文件中的所有的检查
@SuppressLint("all")

使用Annotations来检查代码 (Support-Annotations library)

Annotations 可以给代码检查工具提供一些提示,来帮助检查微妙的代码问题。
Annotations以元数据的方式添加到 变量、参数、一个方法中的输入参数、返回值等。
当使用了代码检查工具, annotations 可以帮助检查这些问题,比如空指针异常和资源文件类型冲突。

添加基本的注解

想要在代码中使用注解,需要添加 Support-Annotations 库。

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

添加 Nullness Annotations

@Nullable and @NonNull annotations 可以检查一个变量、参数或返回值的null情况。

使用@NonNull 来检查传入的参数不能为空。

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

    /** Add support for inflating the <fragment> tag. */
    @NonNull
    @Override
    public View onCreateView(String name, @NonNull Context context,
      @NonNull AttributeSet attrs) {
      ...
      }
...

Nullability Analysis

Android Studio 支持通过nullability 分析来在代码中动态的推断和插入nullness annotations。为空性分析根据贯穿方法树的几个约定来进行扫描:

这个分析完成后,被检查的地方会动态的加入合适的null annotations。

在 Android Studio 中 进行 nullability的检查,选择Analyze > Infer Nullity
Android Studio会插入 @Nullable and @NonNull annotations 在需要检查的位置。在空指针分析完成后,最好检验一下被注入的annotations。

添加 Resource Annotations

Resource Annotations 校验传入的参数是否为指定的资源类型
@StringRes
@DrawableRes
@DimenRes
@ColorRes
@InterpolatorRes

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

添加 Thread Annotations

Thread annotations 校验一个方法是否在指定的线程中被调用。有以下4中类型:
@UiThread
@MainThread
@WorkerThread
@BinderThread

@MainThread and the @UiThread 可以互换。

添加 Value Constraint Annotations

@IntRange, @FloatRange, @Size 校验传递过来的参数值。

@IntRange 校验是否在指定的整形范围内。例子说明 alpha 参数包含在 0 ~ 255 之间:

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

@FloatRange 检验是否在指定的浮点型范围内。比如确保alpha参数在0.0 to 1.0之间:

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

@Size 校验一个容器或数组的长度。比如,使用@Size(min=1) 来检查一个容器不为空,使用@Size(2)来校验容器确定只有两个值。比如 确定location 数组知识包含一个元素:

int[] location = new int[3];
button.getLocationOnScreen(@Size(min=1) location);

添加Permission Annotations

@RequiresPermission 校验方法调用者的权限。 anyOf 属性用于检查满足一种一个, allOf属性用于检查满足所有 attribute.

setWallpaper 方法必须要有permission.SET_WALLPAPERS 权限.

@RequiresPermission(Manifest.permission.SET_WALLPAPER)
public abstract void setWallpaper(Bitmap bitmap) throws IOException;
@RequiresPermission(allOf = {
    Manifest.permission.READ_EXTERNAL_STORAGE,
    Manifest.permission.WRITE_EXTERNAL_STORAGE})
public static final void copyFile(String dest, String source) {
    ...
}

添加 CheckResults Annotations

@CheckResults 校验方法接口或者返回值是否真的被使用了。
下面的例子表示checkPermissions 方法确定返回值被使用了。如果没使用,就会建议使用 enforcePermission方法来替代。

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

添加 CallSuper Annotations

使用@CallSuper 注解 校验 覆写的方法 需要调用父类的实现方法。
例子,覆写onCreate的方法必须调用super.onCreate()。

 @CallSuper
protected void onCreate(Bundle savedInstanceState) {
}

创建Enumerated Annotations

使用 @IntDef@StringDef 注解 可以创建一个integer 和 string 类型的集合用来校验 其他变量的引用类型,比如传入set中的引用类型。

import android.support.annotation.IntDef;
...
public abstract class ActionBar {
    ...
    //Define the list of accepted constants
    @IntDef({NAVIGATION_MODE_STANDARD, NAVIGATION_MODE_LIST, NAVIGATION_MODE_TABS})

    //Tell the compiler not to store annotation data in the .class file
    @Retention(RetentionPolicy.SOURCE)

    //Declare the NavigationMode annotation
    public @interface NavigationMode {}

    //Declare the constants
    public static final int NAVIGATION_MODE_STANDARD = 0;
    public static final int NAVIGATION_MODE_LIST = 1;
    public static final int NAVIGATION_MODE_TABS = 2;

    //Decorate the target methods with the annotation
    @NavigationMode
    public abstract int getNavigationMode();

    //Attach the annotation
    public abstract void setNavigationMode(@NavigationMode int mode);

译代码的时候,如果mode 类型不在定义中的(NAVIGATION_MODE_STANDARD, NAVIGATION_MODE_LIST, or NAVIGATION_MODE_TABS)时,会有警告产生。

使用flag 可以检查一个参数或者返回值是否引用类型是否在指定的格式中。

import android.support.annotation.IntDef;
...

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

...

参考文档

Improve Your Code with Lint
Improve Code Inspection with Annotations
support-annotations
提高代码质量-工具篇

上一篇下一篇

猜你喜欢

热点阅读