1、Lint介绍以及使用
Android Studio 提供一个名为 Lint 的代码扫描工具,可帮助您发现并纠正代码结构质量的问题,而无需实际执行该应用,也不必编写测试用例。该工具会报告其检测到的每个问题并提供该问题的描述消息和严重级别,以便您可以快速确定需要优先进行哪些关键改进。此外,您可以调低问题的严重级别,忽略与项目无关的问题,也可以调高严重级别,以突出特定问题。
我们除了测试 Android 应用以确保其符合功能要求外,还必须确保代码不存在结构问题。结构混乱的代码会影响 Android 应用的可靠性和效率,增大维护代码的难度。例如,如果 XML 资源文件包含未使用的命名空间,则不仅占用空间,还会导致不必要的处理。其他结构问题,例如使用目标 API 版本不支持的已弃用的元素或 API 调用等,可能导致代码无法正常运行。
从命令行运行 Lint
要对项目目录中的文件列表运行 Lint,请使用以下命令:
|
|
例如,您可以发出以下命令,扫描 myproject 目录及其子目录中的文件。问题 ID MissingPrefix 提示 Lint 仅扫描缺少 Android 命名空间前缀的 XML 属性。
|
|
通过 Gradle 运行 Lint
在 Windows 上:
|
|
在 Linux 或 Mac 上:
|
|
如果您只想为特定buildType运行 lint 任务,您必须大写变体名称并在其前面加上 lint 前缀。
|
|
在Java文件和XML文件中配置对Lint的检查忽略
下例说明了如何对 APPSignalInfoActivity 类中的 SetTextI18n 问题关闭 Lint 检查:
|
|
下例说明了如何对一个xml布局文件 view_call_key_0.xml 中的 HardcodedText 问题关闭Lint检查:
|
|
要禁止检查 Java 或 xml 文件中的所有 Lint 问题,可使用 all 关键字:
|
|
|
|
配置 Lint 文件
|
|
通过Gradle配置Lint选项
|
|
LintOptions所有配置项参考:
http://google.github.io/android-gradle-dsl/current/com.android.build.gradle.internal.dsl.LintOptions.html
如何在项目中使用lint检查
- 在我们的代码或者xml文件中相应区域可以看到lint检查出来的警告信息:
- 如何使lint检查出error时打断Run?
首先,设置abortOnError为true:
|
|
之后:
- Jenkins默认启用Lint检查,只要在build.gradle中设置abortOnError为true即可:
|
|
如何忽略某个moudle的检查
有时候我们项目中的某一个moudle是用来测试的,本身不用很关心代码的质量问题,这时候,我们可以在该moudle的build.gradle中做如下设置:
|
|
注:
- 在多个moudle的项目中,如果某个moudle有一个error或者warning,那么用右键—>open in browser的方式打开html report,有可能会显示不出来,所以为了保险起见,最好在每一个moudle下直接打开这个report html文件 或者 xml文件
- 不同Lint版本的默认开启的check项略有不同,最好打开checkAllWarnings,之后再根据需求ignore
更多参考:https://developer.android.com/studio/write/lint.html
2、扩展:自定义lint
主要参考了美团的Android自定义Lint实践和官方源码
主要使用LinkedIn发方案:将jar放到一个aar中:Writing Custom Lint Checks with Gradle。
这里举一个检查在循环体内(for, foreach, while, do-while)进行内存分配(Allocation)的例子。我们知道,在循环体内进行内存分配,如果这个循环次数很多的话,我们这么大频次的内存分配是有性能上的损耗的,甚至会引起内存抖动或者内存泄漏。一个比较合理的方案是,使用对象池技术来替代频繁的内存分配(可以了解Message.obtion()就是一种对象池技术)
由于官方的Lint没有这样的chek项,所以需要自定义。
大体步骤如下:
创建Java工程,配置Gradle
|
|
创建Detector
Detector负责扫描代码,发现问题并报告。这里主要参考了studio自带Lint检查的官方源码JavaPerformanceDetector
|
|
核心在于:监听for、foreach、while、do-while的访问节点,在节点中判断是否有new对象的行为(visitNewExpression),然后再判断是不是“LazilyInitialized”,去做相关告警提示。
Issue
可以看到,在GuoJavaPerformanceDetector.java中有一个Issue对象LOOP_ALLOC,其作用是提供给registry,最终体现在Lint report中。
Issue.create的各参数对应如下:
id : 唯一值,应该能简短描述当前问题。利用Java注解或者XML属性进行屏蔽时,使用的就是这个id。
summary : 简短的总结,通常5-6个字符,描述问题而不是修复措施。
explanation : 完整的问题解释和修复建议。
category : 问题类别。详见下文详述部分。
priority : 优先级。1-10的数字,10为最重要/最严重。
severity : 严重级别:Fatal, Error, Warning, Informational, Ignore。
Implementation : 为Issue和Detector提供映射关系,Detector就是当前Detector。声明扫描检测的范围Scope,Scope用来描述Detector需要分析时需要考虑的文件集,包括:Resource文件或目录、Java文件、Class文件。
IssueRegistry
|
|
在build.grade中声明Lint-Registry属性
|
|
新建一个android lib moudle lint_aar
lint_aar的build.gradle需要配置如下:
|
|
之后我们的待检测moudle依赖这个aar moudle,或者直接使用aar方式依赖即可
相关代码:https://github.com/guoxiaojiang/testlint
3、总结&感悟
代码规范标准化,追求卓越工匠精神,打磨精品代码
我们的工程是由一砖一瓦打造成的,容不得半点疏忽,如果容忍这些砖瓦有任何的瑕疵,那很有可能眼看他起高楼,眼看他宴宾客,眼看他楼塌了。在编码的过程中,我们一定注重细节,细节决定成败,Java部分这里推荐大家阅读阿里的阿里巴巴Java开发手册作参考