使用 Lint 检查改进代码

除了构建测试以确保您的应用满足其功能要求外,还必须通过 lint 工具运行代码以帮助确保代码没有结构问题。lint 工具有助于查找可能影响 Android 应用可靠性和效率并使代码难以维护的结构不良的代码。强烈建议您在发布应用之前更正 lint 检测到的任何错误。

例如,如果您的 XML 资源文件包含未使用的命名空间,则会占用空间并需要不必要的处理。其他结构问题,例如使用已弃用的元素或目标 API 版本不支持的 API 调用,可能会导致代码无法正确运行。Lint 可以帮助您解决这些问题。

为了提高 lint 的性能,您还可以在代码中添加注释

概述

Android Studio 提供了一个名为 lint 的代码扫描工具,它可以帮助您识别和纠正代码结构质量方面的问题,而无需执行应用或编写测试用例。该工具检测到的每个问题都会附带描述消息和严重级别,以便您可以优先处理需要进行的关键改进。您还可以降低问题的严重级别以忽略与您的项目无关的问题,或提高严重级别以突出显示特定问题。

lint 工具会检查您的 Android 项目源文件是否存在潜在的错误和优化改进,以确保正确性、安全性、性能、可用性、可访问性和国际化。使用 Android Studio 时,配置的 lint 和 IDE 检查会在您构建应用时运行。但是,您可以手动运行检查从命令行运行 lint,如本页所述。

内置的 lint 工具在您使用 Android Studio 时会检查您的代码。您可以通过两种方式查看警告和错误

  • 作为编辑器窗口中的弹出文本。当 lint 发现问题时,它会以黄色突出显示有问题的代码。对于更严重的问题,它会以红色下划线标注代码。
  • 在您点击代码 > 检查代码时的 lint 检查结果窗口中。

注意:当您的代码在 Android Studio 中编译时,还会运行额外的IntelliJ 代码检查以简化代码审查。

图 1 显示了 lint 工具如何处理应用源文件。

Code scanning workflow with the lint tool.
图 1. 使用 lint 工具的代码扫描工作流程。
应用源文件
源文件由构成您的 Android 项目的文件组成,包括 Kotlin、Java 和 XML 文件、图标和 ProGuard 配置文件。
lint.xml 文件
一个配置文件,您可以使用它来指定要排除的任何 lint 检查以及自定义问题严重级别。
lint 工具
一个静态代码扫描工具,您可以从命令行或在 Android Studio 中对您的 Android 项目运行。lint 工具会检查可能影响 Android 应用质量和性能的结构化代码问题。
lint 检查结果
您可以在控制台或 Android Studio 中的检查结果窗口中查看 lint 的结果。如果您从命令行运行lint,则结果将写入build/文件夹。有关更多详细信息,请参阅有关手动运行检查的部分。

从命令行运行 lint

如果您使用的是 Android Studio 或 Gradle,请使用Gradle 包装器通过从项目的根目录输入以下命令之一来调用项目的lint任务

  • 在 Windows 上
    gradlew lint
    
  • 在 Linux 或 macOS 上
    ./gradlew lint
    

您应该会看到类似以下内容的输出

> Task :app:lintDebug
Wrote HTML report to file:<path-to-project>/app/build/reports/lint-results-debug.html

当 lint 工具完成其检查后,它会提供 lint 报告的 XML 和 HTML 版本的路径。然后,您可以导航到 HTML 报告并在浏览器中打开它,如图 2 所示。

Sample HTML lint report
图 2. HTML lint 报告示例。

如果您的项目包含构建变体,则 lint 仅检查默认变体。如果要对其他变体运行 lint,则必须将变体名称大写并在其前面加上lint

./gradlew lintRelease

要了解有关从命令行运行 Gradle 任务的更多信息,请阅读从命令行构建您的应用

使用独立工具运行 lint

如果您未使用 Android Studio 或 Gradle,请安装Android SDK 命令行工具以使用独立 lint 工具。在android_sdk/cmdline-tools/version/bin/lint中找到 lint 工具。

注意:如果您尝试在 Gradle 项目上运行独立工具,则会产生错误。您应始终使用gradle lint(在 Windows 上)或./gradlew lint(在 macOS 或 Linux 上)在 Gradle 项目上运行 lint。

要对项目目录中的一系列文件运行 lint,请使用以下命令

lint [flags] <project directory>

例如,您可以发出以下命令来扫描myproject目录及其子目录下的文件。问题 ID MissingPrefix 告诉 lint 仅扫描缺少 Android 命名空间前缀的 XML 属性。

lint --check MissingPrefix myproject 

要查看工具支持的完整标志和命令行参数列表,请使用以下命令

lint --help

以下示例显示了对名为 Earthquake 的项目运行 lint 命令时的控制台输出

$ lint Earthquake

Scanning Earthquake: ...............................................................................................................................
Scanning Earthquake (Phase 2): .......
AndroidManifest.xml:23: Warning: <uses-sdk> tag appears after <application> tag [ManifestOrder]
  <uses-sdk android:minSdkVersion="7" />
  ^
AndroidManifest.xml:23: Warning: <uses-sdk> tag should specify a target API level (the highest verified version; when running on later versions, compatibility behaviors may be enabled) with android:targetSdkVersion="?" [UsesMinSdkAttributes]
  <uses-sdk android:minSdkVersion="7" />
  ^
res/layout/preferences.xml: Warning: The resource R.layout.preferences appears to be unused [UnusedResources]
res: Warning: Missing density variation folders in res: drawable-xhdpi [IconMissingDensityFolder]
0 errors, 4 warnings

示例输出列出了四个警告和零个错误。

两个警告与项目的AndroidManifest.xml文件有关

  • ManifestOrder
  • UsesMinSdkAttributes
一个警告与Preferences.xml布局文件有关:UnusedResources

一个警告与res目录有关:IconMissingDensityFolder

配置 lint 以抑制警告

默认情况下,当您运行 lint 扫描时,该工具会检查 lint 支持的所有问题。您还可以限制 lint 要检查的问题,并且可以为问题分配严重级别。例如,您可以抑制对与您的项目无关的特定问题的 lint 检查,并且可以配置 lint 以较低的严重级别报告非关键问题。

严重级别为

  • 启用
  • 禁用忽略
  • 信息性
  • 警告
  • 错误
  • 严重错误

您可以为不同级别配置 lint 检查

  • 全局(整个项目)
  • 项目模块
  • 生产模块
  • 测试模块
  • 打开的文件
  • 类层次结构
  • 版本控制系统 (VCS) 范围

配置 lint 文件

您可以在lint.xml文件中指定您的 lint 检查首选项。如果您要手动创建此文件,请将其放在 Android 项目的根目录中。

lint.xml文件包含一个包含一个或多个子<issue>元素的封闭<lint>父标记。Lint 为每个<issue>定义了一个唯一的id属性值

<?xml version="1.0" encoding="UTF-8"?>
<lint>
    <!-- list of issues to configure -->
</lint>

要更改问题的严重级别或禁用对该问题的 lint 检查,请在<issue>标记中设置严重性属性。

提示:有关 lint 支持的问题及其对应问题 ID 的完整列表,请运行lint --list命令。

lint.xml 文件示例

以下示例显示了lint.xml文件的内容

<?xml version="1.0" encoding="UTF-8"?>
<lint>
    <!-- Disable the IconMissingDensityFolder 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>

此示例显示了如何报告不同问题类型。IconMissingDensityFolder检查完全禁用,而ObsoleteLayoutParam检查仅在封闭的<ignore ... />声明中指定的文件中禁用。

为 Kotlin、Java 和 XML 源文件配置 lint 检查

您可以在首选项对话框中关闭 Kotlin、Java 和 XML 源文件的 lint 检查

  1. 选择文件 > 设置(在 Windows 上)或Android Studio > 首选项(在 macOS 或 Linux 上)。
  2. 选择编辑器 > 检查
  3. 要禁用,请取消选择相应的源文件。

您可以通过选择相应的配置文件为 IDE 或单个项目设置这些选项。

在 Java 或 Kotlin 中配置 lint 检查

要专门为 Android 项目中的类或方法禁用 lint 检查,请将@SuppressLint注释添加到该代码中。

以下示例显示了如何在onCreate方法中关闭NewApi问题的 lint 检查。lint 工具将继续检查此类中其他方法的NewApi问题。

Kotlin

@SuppressLint("NewApi")
override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.main)

Java

@SuppressLint("NewApi")
@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

在任何 Composable 上都可以实现相同的功能。以下代码片段显示了如何在任何 Composable 上关闭NewApi检查。

Kotlin

  @SuppressLint("NewApi")
  @Composable
  fun MyComposable{
    ...
  }
  

以下示例显示了如何在FeedProvider类中关闭ParserError问题的 lint 检查

Kotlin

@SuppressLint("ParserError")
class FeedProvider : ContentProvider() {

Java

@SuppressLint("ParserError")
public class FeedProvider extends ContentProvider {

要抑制对文件中所有 lint 问题的检查,请使用all关键字

Kotlin

@SuppressLint("all")

Java

@SuppressLint("all")

您可以使用相同的注释来抑制任何 Composable 函数上的 lint 检查。

在 XML 中配置 lint 检查

使用tools:ignore属性关闭 XML 文件特定部分的 lint 检查。将以下命名空间值放在lint.xml文件中,以便 lint 工具识别该属性

namespace xmlns:tools="http://schemas.android.com/tools"

以下示例显示了如何在 XML 布局文件的<LinearLayout>元素中关闭UnusedResources问题的 lint 检查。ignore属性由声明该属性的父元素的子元素继承。在此示例中,lint 检查也针对子<TextView>元素禁用

<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"

要抑制对 XML 元素中所有 lint 问题的检查,请使用all关键字

tools:ignore="all"

使用 Gradle 配置 lint 选项

Gradle 的 Android 插件允许您配置某些 lint 选项,例如要运行或忽略哪些检查,方法是在模块级build.gradle文件中使用 lint{}块。

以下代码片段显示了一些您可以配置的属性

Kotlin

android {
    ...
    lint {
        // Turns off checks for the issue IDs you specify.
        disable += "TypographyFractions" + "TypographyQuotes"
        // Turns on checks for the issue IDs you specify. These checks are in
        // addition to the default lint checks.
        enable += "RtlHardcoded" + "RtlCompat" + "RtlEnabled"
        // To enable checks for only a subset of issue IDs and ignore all others,
        // list the issue IDs with the 'check' property instead. This property overrides
        // any issue IDs you enable or disable using the properties above.
        checkOnly += "NewApi" + "InlinedApi"
        // If set to true, turns off analysis progress reporting by lint.
        quiet = true
        // If set to true (default), stops the build if errors are found.
        abortOnError = false
        // If set to true, lint only reports errors.
        ignoreWarnings = true
        // If set to true, lint also checks all dependencies as part of its analysis.
        // Recommended for projects consisting of an app with library dependencies.
        checkDependencies = true
    }
}
...

Groovy

android {
    ...
    lint {
        // Turns off checks for the issue IDs you specify.
        disable 'TypographyFractions','TypographyQuotes'
        // Turns on checks for the issue IDs you specify. These checks are in
        // addition to the default lint checks.
        enable 'RtlHardcoded','RtlCompat', 'RtlEnabled'
        // To enable checks for only a subset of issue IDs and ignore all others,
        // list the issue IDs with the 'check' property instead. This property overrides
        // any issue IDs you enable or disable using the properties above.
        checkOnly 'NewApi', 'InlinedApi'
        // If set to true, turns off analysis progress reporting by lint.
        quiet true
        // If set to true (default), stops the build if errors are found.
        abortOnError false
        // If set to true, lint only reports errors.
        ignoreWarnings true
        // If set to true, lint also checks all dependencies as part of its analysis.
        // Recommended for projects consisting of an app with library dependencies.
        checkDependencies true
    }
}
...

覆盖给定问题的严重级别所有 lint 方法都遵循配置顺序。例如,在finalizeDsl()中将问题设置为严重错误会覆盖在主 DSL 中禁用它的操作。

创建警告基线

您可以对项目的当前警告集进行快照,然后将快照用作未来检查运行的基线,以便仅报告新问题。基线快照允许您开始使用 lint 使构建失败,而无需首先返回并解决所有现有问题。

要创建基线快照,请修改项目的build.gradle文件,如下所示

Kotlin

android {
    lint {
        baseline = file("lint-baseline.xml")
    }
}

Groovy

android {
    lintOptions {
        baseline file("lint-baseline.xml")
    }
}

第一次添加此行时,将创建lint-baseline.xml文件以建立您的基线。从那时起,工具仅读取该文件以确定基线。如果要创建新的基线,请手动删除该文件并再次运行 lint 以重新创建它。

然后,通过选择**代码 > 检查代码**从 IDE 中运行 lint,或按如下方式从命令行运行。输出打印 lint-baseline.xml 文件的位置。您的设置的文件位置可能与此处显示的不同。

$ ./gradlew lintDebug -Dlint.baselines.continue=true
...
Wrote XML report to file:///app/lint-baseline.xml
Created baseline file /app/lint-baseline.xml

运行 lint 会将当前的所有问题记录在 lint-baseline.xml 文件中。当前问题集称为基线。如果要与其他人共享,可以将 lint-baseline.xml 文件检入版本控制。

自定义基线

如果只想将某些问题类型添加到基线,请通过如下编辑项目的 build.gradle 文件来指定要添加的问题。

Kotlin

android {
    lint {
        checkOnly += "NewApi" + "HandlerLeak"
        baseline = file("lint-baseline.xml")
    }
}

Groovy

android {
    lintOptions {
        checkOnly 'NewApi', 'HandlerLeak'
        baseline file("lint-baseline.xml")
    }
}

如果在创建基线后向代码库添加了任何新的警告,lint 仅列出新引入的错误。

基线警告

在基线生效时,您会收到一条信息性警告,告知您由于某些问题已列在基线中,因此已将其过滤掉。此警告可帮助您记住已配置基线,并且需要在某个时间点修复所有问题。

此信息性警告还会跟踪不再报告的问题。此信息可让您知道是否已实际修复问题,因此您可以选择重新创建基线以防止错误在未检测到的情况下再次出现。

注意:当您在 IDE 中以批处理模式运行检查时,基线处于启用状态,但在您编辑文件时在后台运行的编辑器内检查中会忽略它们。这是因为基线适用于代码库存在大量现有警告但您确实希望在触及代码时修复本地问题的情况。

手动运行检查

要手动运行已配置的 lint 和其他 IDE 检查,请选择**代码 > 检查代码**。检查结果将显示在**检查结果**窗口中。

设置检查范围和配置文件

按如下方式选择要分析的文件(检查范围)和要运行的检查(检查配置文件)。

  1. 在**Android**视图中,打开您的项目并选择要分析的项目、文件夹或文件。
  2. 从菜单栏中,选择**代码 > 检查代码**。
  3. 在**指定检查范围**对话框中,查看设置。

    Specify Inspection Scope
    图 3. 查看检查范围设置。

    出现在**指定检查范围**对话框中的选项会根据您选择的是项目、文件夹还是文件而有所不同。

    • 当您选择一个项目、文件或目录时,**指定检查范围**对话框会显示您选择的项目、文件或目录的路径。
    • 当您选择多个项目、文件或目录时,**指定检查范围**对话框会显示**所选文件**的选中单选按钮。

    要更改要检查的内容,请选择其他单选按钮之一。有关**指定检查范围**对话框上所有可能字段的说明,请参阅指定检查范围对话框

  4. 在**检查配置文件**下,选择要使用的配置文件。
  5. 单击**确定**以运行检查。

    图 4 显示了来自**检查代码**运行的 lint 和其他 IDE 检查结果。

    Select an issue to see its resolution.
    图 4. 检查结果。选择一个问题以查看解决方案。
  6. 在**检查结果**窗格中,通过展开和选择错误类别、类型或问题来查看检查结果。

    **检查报告**窗格显示**检查结果**窗格中选择的错误类别、类型或问题的检查报告,并显示错误的名称和位置。在适用的情况下,检查报告会显示其他信息(例如问题摘要),以帮助您更正问题。

  7. 在**检查结果**窗格的树状视图中,右键单击类别、类型或问题以显示上下文菜单。

    根据上下文,您可以

    • 跳转到源代码。
    • 排除和包含选定的项目。
    • 禁止显示问题。
    • 编辑设置。
    • 管理检查警报。
    • 重新运行检查。

有关工具栏按钮、上下文菜单项和检查报告字段的说明,请参阅检查结果工具窗口

使用自定义范围

按如下方式使用 Android Studio 中提供的自定义范围之一。

  1. 在**指定检查范围**对话框中,选择**自定义范围**。
  2. 单击**自定义范围**列表以显示您的选项。

    Choose Inspection Scope
    图 5. 选择要使用的自定义范围。
    • 所有位置:所有文件。
    • 项目文件:当前项目中的所有文件。
    • 项目源文件:仅当前项目中的源文件。
    • 项目生产文件:仅当前项目中的生产文件。
    • 项目测试文件:仅当前项目中的测试文件。
    • 草稿和控制台:仅当前项目中打开的草稿文件和控制台。
    • 最近查看的文件:仅当前项目中最近查看的文件。
    • 当前文件:仅当前项目中的当前文件。当您选择文件或文件夹时出现。
    • 选定的目录:仅当前项目中的当前文件夹。当您选择文件夹时出现。
    • 类层次结构:当您选择此选项并单击**确定**时,会显示一个对话框,其中包含当前项目中的所有类。在对话框中,使用**按名称搜索**字段筛选和选择要检查的类。如果您不筛选类列表,代码检查将检查所有类。

    如果已为项目配置 VCS,则还有选项可以将搜索限制为仅修改过的文件。

  3. 单击**确定**。

创建自定义范围

当您想要检查任何当前可用的自定义范围都不涵盖的文件和目录的选择时,您可以创建自定义范围。

  1. 在**指定检查范围**对话框中,选择**自定义范围**。
  2. 单击**自定义范围**列表后的三个点。

    Specify Inspection Scope dialog
    图 6. 指定检查范围对话框。

    将显示**范围**对话框。

    Create a custom scope
    图 7. 创建自定义范围。
  3. 单击对话框左上角的按钮以定义新的范围。
  4. 在出现的**添加范围**列表中,选择**本地**。

    本地范围和共享范围都在项目中用于**检查代码**功能。共享范围也可用于具有范围字段的其他项目功能。例如,当您单击**编辑设置**以更改查找用法的设置时,结果对话框将具有一个**范围**字段,您可以在其中选择共享范围。

    Select a shared scope from the Find Usages dialog
    图 8. 从**查找用法**对话框中选择共享范围。
  5. 为范围命名,然后单击**确定**。

    **范围**对话框的右侧窗格将填充可用于定义自定义范围的选项。

  6. 从列表中,选择**项目**。

    将显示可用项目的列表。

    注意:您可以为项目或包创建自定义范围。步骤相同。

  7. 展开项目文件夹,选择要添加到自定义范围的内容,然后选择是包含还是排除它。

    Define a custom scope
    图 9. 定义自定义范围。
    • 包含:包含此文件夹及其文件,但不包含其任何子文件夹。
    • 递归包含:包含此文件夹及其文件以及其子文件夹及其文件。
    • 排除:排除此文件夹及其文件,但不排除其任何子文件夹。
    • 递归排除:排除此文件夹及其文件以及其子文件夹及其文件。

    图 10 显示包含了main文件夹,并且javares文件夹被递归包含。蓝色表示部分包含的文件夹,绿色表示递归包含的文件夹和文件。

    Example pattern for a custom scope
    图 10. 自定义范围的示例模式。
    • 如果选择java文件夹并单击递归排除,则java文件夹及其下所有文件夹和文件上的绿色突出显示将消失。
    • 如果选择绿色突出显示的MainActivity.kt文件并单击排除,则MainActivity.kt不再以绿色突出显示,但java文件夹下的所有其他内容仍然以绿色突出显示。
  8. 单击**确定**。自定义范围将显示在列表的底部。

查看和编辑检查配置文件

Android Studio 有一系列 lint 和其他检查配置文件,这些配置文件会通过 Android 更新进行更新。您可以按原样使用这些配置文件,也可以编辑其名称、说明、严重性和范围。您还可以激活和停用整个配置文件组或组内的单个配置文件。

要访问**检查**设置

  1. 选择**文件 > 设置**。(在 Windows 上)或**Android Studio > 首选项**(在 macOS 或 Linux 上)。
  2. 选择编辑器 > 检查
  3. **检查**窗格显示支持的检查及其说明的列表。

    Supported inspections and their descriptions
    图 11. 支持的检查及其说明。
  4. 选择**配置文件**列表以在**默认值**(Android Studio)和**项目默认值**(活动项目)检查之间切换。

    有关更多信息,请参阅 IntelliJ 的管理配置文件页面。

  5. 在左侧窗格的**检查**列表中,选择顶级配置文件类别或展开组并选择特定配置文件。

    选择配置文件类别时,可以将该类别中的所有检查作为一个检查进行编辑。

  6. 选择**显示架构操作**Show Schema Actions icon列表以复制、重命名、向检查添加说明以及导出和导入检查。
  7. 完成后,单击**确定**。