使用 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会黄色高亮有问题的代码,或使用红色下划线指示严重的问题。
- 手动
Analyze > Inspect Code
之后,在检查结果窗口中。
设置默认的Lint 检查:
- 打开项目,选择 File > Other Settings > Default Settings,选择 Editor > Inspections.
- 在Profile 选项中,选择 Default or Project Default来选择是全局作用域还是project作用域。
- 在窗口中进行设置。
配置手动执行的Lint检查:
- 打开项目,选择你要测试的目录。使用
Analyze > Inspect Code.
- 在指定检查范围弹出框中,选择检查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检查.
- 在java文件中
@SuppressLint
注解可以让Java class 或者方法不用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")
- 在XML文件中
使用tools:ignore
属性来禁止XML文件制定区域的Lint 检查。父控件的ignore属性会被子控件继承。
关闭"UnusedResources "的问题检查。
关闭多个问题检查<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" tools:ignore="UnusedResources" > <TextView android:text="@string/auto_update_prompt" /> </LinearLayout>
关闭所有的问题检查tools:ignore="NewApi,StringFormatInvalid"
tools:ignore="all"
使用Annotations来检查代码 (Support-Annotations library)
Annotations 可以给代码检查工具提供一些提示,来帮助检查微妙的代码问题。
Annotations以元数据的方式添加到 变量、参数、一个方法中的输入参数、返回值等。
当使用了代码检查工具, annotations 可以帮助检查这些问题,比如空指针异常和资源文件类型冲突。
添加基本的注解
想要在代码中使用注解,需要添加 Support-Annotations 库。
- 可以通过Android Studio 来添加
- 或者直接在gradle.xml中添加
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
提高代码质量-工具篇
网友评论