Android Studio 的代码检查功能,使用 Lint 工具优化代码(笔记)

Android 同时被 2 个专栏收录
23 篇文章 0 订阅
8 篇文章 0 订阅

最近在看一篇 Android 开发规范(完结版),收获颇多。

10.21 里推荐了 Lint 工具,好吧,我以前还真不知道这个 (°ー°〃)。正好在写一个 demo,就此记录一下使用 Android Studio 自带的 Lint 工具帮助优化代码的过程吧~

文中 缩进部分段落 是摘抄自引用的博客~引用结束处标明了出处~

本人英语水平有限,若有翻译错误,欢迎讨论和指正~

-------------------------------------------------------------

右键 module、目录或者文件,选择 Analyze -> Inspect Code,打开 Lint 代码检查结果窗口。

整体目录如下,可以看到有很多种类型的 warning:


我们依次来看看吧。

1. Android Lint: Performance 性能

双击查看详情,有 2 种性能方面的警告。


(1)Overdraw: Painting regions more than once. 过度绘制:绘制区域超过了 1 次。

单击此行,右侧会出现详细描述,左侧会提示你需要修改的地方。


右侧方框里的内容大概翻译一下:

如果你在根布局 root view 里设置了背景 background,那么你应该使用一个自定义的主题 theme 并将主题的背景 theme background 设置为 null。否则,绘制时将会先绘制主题背景,只有这样才能使你的自定义背景完全覆盖它;这称作“过度绘制”。

注:这个检测器依赖 基于扫描 Java 代码来找出哪些布局和活动相关联,并且它目前正在使用一种不精确的模式匹配算法。因此,它可能会错误地推断出布局与哪个活动相关,然后错误地抱怨背景主题被隐藏了。

如果你想在多个页面使用你的自定义背景,那么你应该考虑使用该自定义背景创建自定义主题,只使用这个自定义主题而不是根元素背景。

当然,也有可能你的自定义 drawable 是半透明的,并且你希望让它与背景混合在一起。然而,如果你预先将背景和你的 drawable 混合在一起,然后使用由此生成的图片或者颜色作为自定义主题的背景,你将得到更好的性能。
总结一下:

如果页面根布局需要使用指定的背景,那么最好是创建一个自定义的主题并将 background 设置为 null,然后再在单独的页面根布局中为其指定需要的背景。

如果你的背景是需要将半透明的 drawable 和背景混合在一起,那么为了得到更好的性能,最好也是创建一个自定义的主题,将 background 设置为 混合后得到的图片或颜色。
如果你的页面要统一使用相同的背景色,那就直接在 styles 里修改主题的背景色吧。
那么到底怎么改呢?

在原先的主题里添加如下一行代码,将 windowBackground 设置为 null。设置为空后布局默认展示效果为黑色背景。

<item name="android:windowBackground">@null</item>
再重新运行一下 代码检查,可以发现这条警告没有啦。

更多关于过度绘制,可见 Android性能优化-过度绘制解决方案

(2)Unused resources. 没有使用过的资源。


Unused resources make applications larger and slow down builds.

这个很好理解,没有使用过的资源文件会增加应用的大小,以及减慢 build 速度。

右侧第一行给出了几个解决方案。

第二个很好理解,"Remove All Unused Resources(移除所有没有使用的资源)",就是直接删除掉。

第一个方案呢?红框里的 "Add a tools:keep attribute to mark as implicitly used(添加 tools:keep 属性来标记隐式使用)",我理解为,大概就是,这个资源目前项目代码里没有用到它,但是以后可能会用到它,需要保留,那就用 tools:keep 来假装使用它吧~

看看报警告的源代码:


点击一下红框按钮后:


XML 文件的根元素 resources 里自动添加了 tools 命名空间。

没有使用过的资源,属性里自动添加了 "tools:keep" 代码。

那这个是什么意思呢?

tools:keep

适用于 <resources> 资源标签

当开启了资源压缩(shrinking resource)功能时,这个属性允许你指定哪些资源需要被保留。

因为开启了资源压缩功能后,未被引用的资源文件会在构建过程中被移除,而部分使用 [Resources.getIdentifier()

](https://developer.android.google.cn/reference/android/content/res/Resources.html#getIdentifier(java.lang.String, java.lang.String, java.lang.String)) 进行引用的资源文件可能被误删。

此时我们可以使用该属性 指定哪些资源需要保留,不能被移除

<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:tools="http://schemas.android.com/tools"
    tools:keep="@layout/used_1,@layout/used_2,@layout/*_3" />

(摘自:Android开发技巧之xml tools属性详解

"tools" 还有更多实用的功能,比如 预览界面

摘抄一段简介:

开发人员在设计 Android Layout 布局时,总会伴随着一些乱七八槽的困扰。比如,为了更加逼真的真实数据预览效果,我们在开发时会将 TextView 的 text 属性写上一些假数据,而当运行到模拟器或真机上时这些假数据就成了造成体验上甚至测试 BUG 的脏数据,又需要一一清除。再比如,我们想在 XML 的预览界面上就看到 ListView 的 Item 内容,而不是只有通过编译运行时才能查看。等等,诸如这些存在于开发 Layout 内容阶段的困扰,都可以通过 Tools Attributes 得以解决。

Android 提供了一种特殊的 tools 命名空间,来帮助开发人员在开发 Layout 布局时使用 tools 属性解决实时预览等问题。这种属性在应用打包运行时将会被忽略,不产生任何影响

(摘自:Android Tools Attributes,让布局设计所见即所得

这个功能是不是特别棒~!

更多关于 "tools" 属性,可以看看这 2 篇博客:

入门 Android Tools Attributes,让布局设计所见即所得 ,

进阶 Android开发技巧之xml tools属性详解

以及 官方文档:Tools Attributes Reference

2. Android Lint: Security. 安全

AllowBackup/FullBackupContent Problems 备份


太长了没法截图,我复制下来了。

On SDK version 23 and up, your app data will be automatically backed up and restored on app install. Consider adding the attribute 'android:fullBackupContent' to specify an '@xml' resource which configures which files to backup. More info: <a href="https://developer.android.com/training/backup/autosyncapi.html">https://developer.android.com/training/backup/autosyncapi.html</a>

在 23 及更高的 SDK 版本中,你的 app 数据将会在 app 安装时自动备份和重新恢复。考虑添加属性 "android:fullBackupContent" 来指定一个 "@xml" 资源,该资源配置哪些文件需要备份。更多信息:https://developer.android.com/training/backup/autosyncapi.html

右侧:

AllowBackup/FullBackupContent Problems  备份问题

--------------------------

The allowBackup attribute determines if an application's data can be backed up and restored. It is documented at http://developer.android.com/reference/android/R.attr.html#allowBackup.

"allowBackup" 属性确定应用程序的数据是否可以备份和恢复。文档见 http://developer.android.com/reference/android/R.attr.html#allowBackup。

--------------------------

By default, this flag is set to true. When this flag is set to true, application data can be backed up and restored by the user using adb backup and adb restore.  

默认情况下,此标志设为true。当此标志设置为true时,用户可以使用 adb backup 和 adb restore 备份和还原应用程序数据。

--------------------------

This may have security consequences for an application. adb backup allows users who have enabled USB debugging to copy application data off of the device. 

这可能对应用程序产生安全性后果。adb backup 允许启用USB调试的用户复制设备上的应用程序数据。

Once backed up, all application data can be read by the user. adb restore allows creation of application data from a source specified by the user. 

一旦备份,所有应用程序数据都可以被用户读取。adb restore 允许从用户指定的源创建应用程序数据。

Following a restore, applications should not assume that the data, file permissions, and directory permissions were created by the application itself.  

数据恢复之后,应用程序不应假设数据、文件权限和目录权限是由应用程序本身创建的。

--------------------------

Setting allowBackup="false" opts an application out of both backup and restore.  To fix this warning, decide whether your application should support backup, and explicitly set android:allowBackup=(true|false)".  

设置 allowBackup="false" 会使应用程序不参与备份和恢复。要修复此警告,请确定你的应用程序是否应该支持备份,并且明确设置 android:allowBackup=(true|false)。

--------------------------

If not set to false, and if targeting API 23 or later, lint will also warn that you should set android:fullBackupContent to configure auto backup. 

如果不设置 allowBackup="false",并且如果目标 API 是 23 或更新,lint 还是会警告你应该设置 android:fullBackupContent 来配置自动备份。

--------------------------

https://developer.android.com/training/backup/autosyncapi.html

Android 自动备份应用程序功能 是 Android 6.0(API 23)新增的。

总结一下:

(1)通常你需要为你的 app 配置 allowBackup="false" 来禁止应用程序数据的备份和恢复功能,否则该属性默认值为 true,会导致安全隐患:用户可以通过 开启USB调试 并使用 adb 命令 复制设备上的应用程序数据并在另一设备上恢复数据(如账号信息等会被盗)。

在 AndroidManifest.xml 文件中 application 的 allowBackup 设置为 false ,禁止数据备份。

android:allowBackup="false"

(2)如果你需要 app 支持 备份恢复某些指定文件,可以使用 android:fullBackupContent 来指定。

① 在 AndroidManifest.xml 文件中 application 里添加 android:fullBackupContent 属性,指定一个包含备份规则的 XML 文件。

android:fullBackupContent="@xml/my_backup_rules"

② 在 res/xml/ 目录中创建一个名为 "my_backup_rules.xml" 的 XML 文件。

其中,<include> 元素指定 备份 哪些文件,<exclude> 元素指定 不备份 哪些文件。

该配置文件的 XML 语法规则如下:(语法规则摘自: 数据存储:数据备份:自动备份

<?xml version="1.0" encoding="utf-8"?>

<full-backup-content>
    <include 
        domain=["file" | "database" | "sharedpref" | "external" | "root"]
        path="string" />
    <exclude 
        domain=["file" | "database" | "sharedpref" | "external" | "root"]
        path="string" />
</full-backup-content>

<full-backup-content> 标签内,你可以定义 <include><exclude> 元素:


- <include> 指定要  备份 的 文件 或 文件夹。 

默认情况下,自动备份几乎包含所有应用程序文件。 如果指定了<include>元素,则系统默认不再包含任何文件,并且仅备份指定的文件。 要包含多个文件,请使用多个 <include> 元素

注意:getCacheDir(),getCodeCacheDir() 或 getNoBackupFilesDir() 返回的目录中的文件总是被排除,即使你尝试包含它们。

- <exclude> 指定在  备份  期间要 排除 的 文件 或 文件夹。 
以下是通常从备份中 排除的一些文件:
Ⅰ. 具有设备特定标识符的文件,由服务器颁发或在设备上生成。 例如,Google Cloud Messaging(GCM)需要在每次用户在新设备上安装您的应用程序时生成注册令牌。 如果旧的注册令牌已恢复,应用程序可能会出现意外。
Ⅱ. 账户凭证或其他 敏感信息。 考虑要求用户在第一次启动还原的应用程序时 重新认证,而不是允许在备份中存储此类信息。
Ⅲ. 与应用程序 调试相关的文件,如即时运行文件。 要排除即时运行文件,请添加规则 <exclude domain =“file”path =“instant-run”/>
Ⅳ. 导致应用超出 25MB 备份配额的 大文件

注:如果你的配置文件指定了这两个元素,则备份 包含由 <include> 元素捕获的所有内容减去 <exclude> 元素中命名的资源。 换句话说,<exclude> 优先

每个元素 必须包含以下 2 个属性:
Ⅰ. domain:指定 资源的位置。 
此属性的有效值包括以下内容:
- root:存储属于此应用程序的所有私有文件的文件系统上的目录。
- 文件:由 getFilesDir() 返回的目录。
- 数据库:由 getDatabasePath() 返回的目录。使用 SQLiteOpenHelper 创建的数据库存储在此处。
- sharedpref:存储 SharedPreferences 的目录。
- 外部由 getExternalFilesDir() 返回的目录。

注:你无法备份这些位置之外的文件

Ⅱ. path:指定要从备份中包含或排除的 文件或文件夹。 注意:
- 此属性 不支持 通配符正则表达式语法。
- 您可以使用 "." 引用当前目录,但是,出于安全考虑,您 无法引用父目录

- 如果指定目录,则该规则适用于目录中的所有文件和递归子目录

(摘自:数据存储:数据备份:自动备份

更多关于 Android 数据备份 详解:数据存储:数据备份:自动备份

更多和 application backup 相关的属性,详见 Android application 和 activity 标签详解

关于 app 备份数据问题的安全隐患,还是值得重视的,可以看看这 2 篇:

详解Android App AllowBackup配置带来的风险

Android应用开发allowBackup敏感信息泄露的一点反思

官方文档:Auto Backup for Apps

3. Android Lint: Usability. 可用性


App is not indexable by Google Search; consider adding at least one Activity with an ACTION-VIEW intent filter. 

App 不能通过谷歌搜索进行索引;考虑至少添加一个使用 ACTION-VIEW intent filter 的 Activity。
Missing support for Firebase App Indexing.

缺少对 Firebase 应用程序的索引支持。

Adds URLs to get your app into the Google index, to get installs and traffic to your app from Google Search. 

添加 URL 使你的应用程序进入谷歌索引,从谷歌搜索获得你的应用程序的安装和流量。

https://g.co/AppIndexing/AndroidStudio

App Links 是安卓 6.0 的一个新特性,允许开发者将 app 和他们的 web 域名关联。这一举措是为了最小化用户遇到“打开方式”对话框的概率。在安卓 M 中,如果一个 app 明确的指定了 app 链接——这个对话框将不复存在。点击一个链接将立即打开官方的 app,没有第三方 app 的机会,更不会打开一个浏览器。虽然这会使安卓更方便,多数情况下,你确实希望点击一个链接打开的是最合适的那个 app,但是对于那些喜欢使用第三方 app 的人来说,似乎是一件坏事。不过这种行为可以在 Android M 的系统设置中关掉。

(摘自:Android M 的"App Links"实现详解

如果你不需要用户在点击某些链接时自动打开你的 app,那么也可以忽略这个警告。

了解更多关于 App Links:

官方英文文档:Add Android App Links ,介绍了如何添加 App Links,附有一个小视频。

视频的翻译可见:[译]Android6.0新特性:App Links

中文版详解:Android M 的"App Links"实现详解

4. Control flow issues. 控制流问题


看右侧的 example 的例子就明白了,警告你这个地方的 if else 里的 return 逻辑可以简化处理。在预览界面点击左上角的按钮,AS 会自动帮你生成简化代码。


5. Declaration redundancy. 声明冗余。


(1)Actual method parameter is the same constant. 实际的方法参数是相同的常数。


This inspection reports methods where a value being passed to a particular parameter appears to be always the same constant.

这个检查报告了传递给方法的特定参数的值似乎始终是相同的常量。

该方法的某个参数在被调用时总是一个固定不变的值,那么就需要考虑一下这个形参是否有声明的必要了。

(2)Declaration access can be weaker. 声明访问权限可以更弱。


This inspection reports all fields, methods or classes, found in the specified inspection scope, that may have their access modifier narrowed down. 

此检查报告了所有在指定的检查范围内找到的字段、方法或类,可以使它们的访问修饰符缩小。

提示你这些字段、方法或类的访问权限可以优化。



(3)Declaration can have final modifier. 声明可以用 final 修饰。


This inspection reports all fields, methods or classes, found in the specified inspection scope, that may have a final modifier added to their declarations.

此检查报告了所有在指定的检查范围内找到的字段、方法或类,它们可以在声明时使用 final 修饰符。

6. Javadoc issues. Javadoc 问题


Reports dangling Javadoc comments. Javadoc comment are dangling if they don't belong to any class, method or field. For example a Javadoc comment in between method declarations that have their own javadoc comments.

报告悬空的 Javadoc 注释。如果 Javadoc 注释不属于任何类、方法或字段,它们就会悬空。例如,在方法声明之间有自己的 Javadoc 注释的 Javadoc 注释。

举个栗子:

/**
 * This is Javadoc comments.
 * 这是 Javadoc 注释。
 */
public void method1(){
	// Do sth.
}

/**
 * This is dangling Javadoc comments.
 * 这是悬空的 Javadoc 注释。请考虑是否需要移除。
 */

/**
 * This is Javadoc comments.
 * 这是 Javadoc 注释。
 */
public void method2(){
	// Do sth.
}

7. Probable bugs. 可能的bug


Constant conditions & exceptions. 固定不变的条件 和 异常。

This inspection analyzes method control and data flow to report possible conditions that are always true or false, expressions whose value is statically proven to be constant, and situations that can lead to nullability contract violations.
	
这种检查 分析 方法控制 和 数据流,以报告 那些可能总是 true 或 false 的条件、其值被静态地证明为常量的表达式,以及 可能导致违反空合约的情况。

---------
Variables, method parameters and return values marked as @Nullable or @NotNull are treated as nullable (or not-null, respectively) and used during the analysis to check nullability contracts, e.g. report NullPointerException (NPE) errors that might be produced.

被 @Nullable 或 @NotNull 标记的变量、方法参数 以及 返回值 被分别视为 可空 或 非空,并在分析期间检查 可空合约,例如:报告可能产生的空指针错误。

---------
More complex contracts can be defined using @Contract annotation, for example:

更多复杂的合约可以使用 @Contract 注解定义,例如:

@Contract("_, null -> null") — method returns null if its second argument is null.

@Contract("_, null -> null") — 如果第二个参数是 null,那么该方法返回 null。

@Contract("_, null -> null; _, !null -> !null") — method returns null if its second argument is null and not-null otherwise.

@Contract("_, null -> null; _, !null -> !null") — 如果第二个参数是 null ,那么该方法返回 null;否则第二个参数若 不是 null,那么该方法也返回 非空值。

@Contract("true -> fail") — a typical assertFalse method which throws an exception if true is passed to it.

@Contract("true -> fail") — 这是一个典型的坚持 参数是 false 的方法,如果传给它一个 true 的参数,那么它会抛出一个异常。

---------
The inspection can be configured to use custom @Nullable @NotNull annotations (by default the ones from annotations.jar will be used)

这个检查可以配置以使用自定义的 @Nullable @NotNull 注解(默认会使用 annotations.jar 里的注解)。

报告可能的 bug,我这里只报告了一处:

Method invocation 'inflate' may produce 'java.lang.NullPointerException'.

"inflate" 方法调用可能会产生 "java.lang.NullPointerException" 空指针异常。

在此处前加一个非空判断即可。

例如:

if (inflater == null) {
    throw new NullPointerException("inflater is null");
}

8. Spelling. 拼写

主要是一些警告你一些单词拼写的不正确啦~


----------------------------------

致谢 & 推荐阅读

(文中相关地方均已标注 引用出处 和 推荐阅读,这里是统一整理在此处,方便大家延伸阅读~)

android studio 使用lint工具优化app时全过程记录

Android性能优化-过度绘制解决方案

Android开发技巧之xml tools属性详解

Android Tools Attributes,让布局设计所见即所得

Tools Attributes Reference

数据存储:数据备份:自动备份

Android application 和 activity 标签详解

详解Android App AllowBackup配置带来的风险

Android应用开发allowBackup敏感信息泄露的一点反思

Auto Backup for Apps

Android M 的"App Links"实现详解

Add Android App Links

[译]Android6.0新特性:App Links

----------------------------------

以后在项目中遇到新的警告,还会陆续更新进来~~












  • 3
    点赞
  • 2
    评论
  • 7
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

©️2021 CSDN 皮肤主题: 编程工作室 设计师:CSDN官方博客 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值