1. 程式人生 > >Android Studio 的程式碼檢查功能,使用 Lint 工具優化程式碼(筆記)

Android Studio 的程式碼檢查功能,使用 Lint 工具優化程式碼(筆記)

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>
再重新執行一下 程式碼檢查,可以發現這條警告沒有啦。

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

"tools" 還有更多實用的功能,比如 預覽介面

摘抄一段簡介:

開發人員在設計 Android Layout 佈局時,總會伴隨著一些亂七八槽的困擾。比如,為了更加逼真的真實資料預覽效果,我們在開發時會將 TextView 的 text 屬性寫上一些假資料,而當執行到模擬器或真機上時這些假資料就成了造成體驗上甚至測試 BUG 的髒資料,又需要一一清除。再比如,我們想在 XML 的預覽介面上就看到 ListView 的 Item 內容,而不是隻有通過編譯執行時才能檢視。等等,諸如這些存在於開發 Layout 內容階段的困擾,都可以通過 Tools Attributes 得以解決。

Android 提供了一種特殊的 tools 名稱空間,來幫助開發人員在開發 Layout 佈局時使用 tools 屬性解決實時預覽等問題。這種屬性在應用打包執行時將會被忽略,不產生任何影響

這個功能是不是特別棒~!

更多關於 "tools" 屬性,可以看看這 2 篇部落格:

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:指定要從備份中包含或排除的檔案或資料夾。 注意:
- 此屬性不支援萬用字元正則表示式語法。
- 您可以使用 "." 引用當前目錄,但是,出於安全考慮,您無法引用父目錄

- 如果指定目錄,則該規則適用於目錄中的所有檔案和遞迴子目錄

關於 app 備份資料問題的安全隱患,還是值得重視的,可以看看這 2 篇:

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 的系統設定中關掉。

如果你不需要使用者在點選某些連結時自動開啟你的 app,那麼也可以忽略這個警告。

瞭解更多關於 App Links:

官方英文文件:Add Android App Links ,介紹瞭如何新增 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. 拼寫

主要是一些警告你一些單詞拼寫的不正確啦~

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

致謝 & 推薦閱讀

(文中相關地方均已標註 引用出處 和 推薦閱讀,這裡是統一整理在此處,方便大家延伸閱讀~)

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

以後在專案中遇到新的警告,還會陸續更新進來~~

相關推薦

no