Android Lint掃描規則說明(二)

主要內容

對Android Studio支持的六類Android Lint規則, 本文主要對Performance包含的32個項的說明,主要內容都是文檔翻譯,適當加一些本身的感想。html

分類詳細說明

高效使用資源

UnusedIds

未被使用的資源id,在layout文件中定義了資源ID從未被使用過,但有時候它們可讓layout更容易閱讀,沒有必要刪除未使用的資源id。java

Overdraw

過分繪製:一個繪製區域被繪製的次數多於一次。android

若是給一個root view設置了背景圖,就要給它設置一個background=nulltheme,不然繪製過程會先繪製themebackground,而後再繪製設置的背景圖,徹底覆蓋以前繪製的theme.background,這是 過分繪製算法

這個檢測器依賴於根據掃描Java代碼找出哪些佈局文件與哪些Activity相關聯,目前它使用的是一種不精確的模式匹配算法。所以,可能會因錯誤地推斷佈局與活動的關聯而給出錯誤的提醒。app

若是想把一個背景圖應用在多個頁面上,能夠考慮自定義theme,並把背景圖設置在theme裏,在layout中設置theme代替設置background。若是背景圖中有透明的部分,而且但願他和theme的背景有層疊效果,那麼能夠選擇先把兩個背景合併成一個背景圖以後,在定義到theme裏。less

VectorPath

關於SVG的使用,給出一篇參考文章:Android vector標籤 PathData 畫圖超詳解,Android Studio能夠建立使用SVG繪製出的drawable圖像資源。ide

UselessLeaf

沒有包含任何View,也沒有設置背景的Layout是多餘的,能夠去掉。讓界面更趨於扁平,嵌套更高效。函數

UselessParent

若是一個包含ViewLayout沒有兄弟層級的Layout,而他的外部ViewGroup又不是ScrollView或者root級別,那麼這個Layout能夠移除,讓他包含的View直接包含在它的父層級的Layout中。讓界面更趨於扁平,嵌套更高效。oop

TooDeepLayout

Layout嵌套過深會影響性能,考慮使用平鋪類型的Layout代替。默認最深的View嵌套是10層,也能夠經過環境變量ANDROID_LINT_MAX_DEPTH進行設置。System.getenv("ANDROID_LINT_MAX_DEPTH");語句獲取,如何設置還沒找到。佈局

TooManyViews

Layout內有太多的View:一個Layout文件內有過多的View會影響性能。考慮使用複合drawables或其餘技巧來減小這個佈局中的視圖數量。默認最多的數量是80個,能夠經過環境變量ANDROID_LINT_MAX_VIEW_COUNT進行設置。聽說這個變量能夠用System.getenv("ANDROID_LINT_MAX_DEPTH");語句獲取,如何設置還沒找到。

NestedWeights

Weight嵌套:使用非0layout-weight值,須要Layout被測量兩次,若是一個包含非0值的LinearLayout被嵌套在另外一個包含非0值的LinearLayout內部,那麼,測量次數就會呈指數級增加。

DuplicateDivider

這個主要是講RecyclerView的分割線,com.android.support:recyclerview-v7 提供了一個類DividerItemDecoration設置分割線樣式,這個類在早期的版本內沒有包含,因此在更新爲新的版本後,可使用這個類從新設置分割線。 具體使用,參考文章:Android RecyclerView 使用徹底解析

MergeRootFrame

FrameLayout在一個layout文件中是root且沒有使用background或者padding等屬性,一般使用一個merge標籤代替FrameLayout會更高效。可是這要看上下文設置,因此在替換以前要確認你已經理解了merge標籤的工做原理

UnusedResources

未使用的資源:多指的是drawable類型的資源。多餘的drawable資源會讓APP變大,編譯過程變長。

InefficientWeight

當LinearLayout只有一個Widget且使用了android:layout_weight時,定義對應的width/height的值爲0dp,Widget就會自動佔滿剩餘空間。由於不須要預先計算本身的尺寸,這種方式更高效。

高效的設置

DisableBaselineAlignment

在使用LinearLayout實現空間的按比例分割時,LinearLayout的空間用layout_weight屬性在所包含的幾個layout中間分割,那麼應該設置被分割LinearLayoutbaseLineAligned="false",這樣能夠加快分割空間所作的運算。

LogConditional

LogConditional:使用android.util.Log打印調試日誌,通常只會在DEBUG模式下使用,在release是不須要打印調試日誌的,在buildToolsVersion大於等於17時, BuildConfig提供兩個一個DEBUG常量來標記是否處於DEBUG模式,咱們能夠用if(BuildConfig.DEBUG){}包裹調試日誌語句,這樣編譯器會在編譯生成release包時,刪除這些語句。若是真的須要在release模式下打印調試日誌,可使用@SuppressLint("LogConditional")註解告訴編譯器在release包中保留這些日誌信息。

UnpackedNativeCode

APP使用System.loadLibrary()加載Native庫時,android 6.0或者更新的版本能夠在Manifest文件中application標籤中添加屬性android:extractNativeLibs="false",這樣能夠提交加載速度,下降APP佔用的存儲空間。

更高效的替代方案

FloatMath

不要使用FloatMath類進行數學計算,推薦使用Math類。

Android早期版本由於浮點運算性能的緣由,推薦使用FloatMath代替Math類進行數學計算。隨着硬件和系統的發展,這個問題已經不復存在,甚至通過JIT優化以後的Math類運算速度會比FloatMath更快,因此,在Android F以上版本的系統上,能夠直接使用Math類,而不是FloatMath。

UseValueOf

某些類構造新對象時,建議使用工廠方法,而不是new關鍵字聲明新的對象。例如,new Intger(0)就可使用Integer.valueOf(0)替代,工廠方法會使用更少的內存,由於它會讓值相等的對象使用同一個實例。

ViewHolder

在給ListViewGradView之類的列表實現Adapter時,不能每次getView調用都去inflate一個新的layout,若是接口參數中給出了一個能夠複用的View對象,就可使用這個對象而不是從新生成。這個應該都很熟悉,也很簡單基礎了。

UseSparseArrays

KeyInteger類型的HashMap可使用SparseArray代替,性能更好。可使用替代HashMap的有SparseBooleanArray、SparseIntArray、SparseLongArray和泛型類SparseArray,每一個對應的類型表明Value的類型。若是在某些狀況必定要用HashMap實現,則能夠用@SuppressLint註解抑制Lint檢查。

WakelockTimeout

關於week lock的使用,這裏提供一篇博客文章:Android 功耗分析之wakelock

UseCompoundDrawables

在一個TextView的四周有隻具備展現做用的ImageView時,建議刪除ImageView改用compound drawables:drawableTop, drawableLeft, drawableRight,drawableBottom,drawablePadding替代方案實現。

有關泄漏的提醒

Recycle

缺乏recycle()調用:許多資源例如:TypedArrays, VelocityTrackers在使用完以後須要調用recycle()方法回收資源。

ViewTag

4.0版本系統以前,View.setTag(int, Object)的實現方式中,會把Object存儲在一個靜態的map裏而且使用的是強引用。這就意味着若是這個Object包含了對Context對象的引用,這個Context就是泄漏了。

傳遞一個View作參數,這個View就能提供一個對建立它的Context的引用。相似的,View holders內包含View,也會有Context與這個View相關聯。

HandlerLeak

Handler引用泄漏:聲明Handler的子類如MyHandler爲內部類,若是MyHandler類對象關聯Looper.getMainLooper()或者Looper.getMainLooper().getQueue()時,會阻止無用的外部類對象被垃圾回收,致使泄漏。若是對應main thread 的關聯,就不會有這個問題。

應對方法,聲明MyHandler爲靜態內部類,並用WeakReference的方式持有一個外部類對象,MyHandler使用這個對象操做外部類的屬性和方法。

DrawAllocation

繪製過程當中的內存分配:避免在佈局繪製過程當中分配內存給新的對象。由於這些操做調用頻率比較高,頻繁分配內存會喚起垃圾回收,中斷UI繪製,致使卡頓。

StaticFieldLeak

非靜態內部類具備對其外部類對象的隱式引用。

若是外部類Fragment或者Activity,那麼這個引用意味着長時間運行的處理程序/加載器/任務(handler/loader/task)將持外部類對象的引用,從而防止外部類對象被回收。

同理,長時間運行的處理程序/加載器/任務(handler/loader/task)對Fragment或者Activity的直接引用,也會形成泄漏。

ViewModel類應該禁止引用View或者non-application類型的Context對象。

代碼提醒

AnimatorKeep

屬性動畫默認支持的屬性以下面列表。若是超出這些範圍,會經過反射調用本地定義的函數。聲明一個屬性動畫對象例如:ObjectAnimator.ofFloat(view, "rotation", 0, 360) 中的「rotation」就是要操做的屬性,若是屬性不在下面的列表中例如ObjectAnimator.ofFloat(view, "position", 0, 360),就須要本地定義一個對應的方法setPosition(float position),而且這個方法須要加上@keep註解,防止被當作無用方法清理掉。

static {
        PROXY_PROPERTIES.put("alpha", PreHoneycombCompat.ALPHA);
        PROXY_PROPERTIES.put("pivotX", PreHoneycombCompat.PIVOT_X);
        PROXY_PROPERTIES.put("pivotY", PreHoneycombCompat.PIVOT_Y);
        PROXY_PROPERTIES.put("translationX", PreHoneycombCompat.TRANSLATION_X);
        PROXY_PROPERTIES.put("translationY", PreHoneycombCompat.TRANSLATION_Y);
        PROXY_PROPERTIES.put("rotation", PreHoneycombCompat.ROTATION);
        PROXY_PROPERTIES.put("rotationX", PreHoneycombCompat.ROTATION_X);
        PROXY_PROPERTIES.put("rotationY", PreHoneycombCompat.ROTATION_Y);
        PROXY_PROPERTIES.put("scaleX", PreHoneycombCompat.SCALE_X);
        PROXY_PROPERTIES.put("scaleY", PreHoneycombCompat.SCALE_Y);
        PROXY_PROPERTIES.put("scrollX", PreHoneycombCompat.SCROLL_X);
        PROXY_PROPERTIES.put("scrollY", PreHoneycombCompat.SCROLL_Y);
        PROXY_PROPERTIES.put("x", PreHoneycombCompat.X);
        PROXY_PROPERTIES.put("y", PreHoneycombCompat.Y);
    }
複製代碼
ObsoleteSdkInt

無用的SDK版本檢查:Android SDK的版本更新比較快,許多API的使用都須要經過檢查SDK版本防止出現not found之類的崩潰。在APP迭代的過程當中提高了minSdkVersion的值就會致使部分SDK版本檢查再也不須要。

這種SDK版本檢查會引發沒必要要的資源搜索。

DevModeObsolete

之前,文檔中建議在productFlavors中建立一個dev product。設定minSdkVersion 21,在開發過程當中激活multidexing加速構建過程。如今已經不須要這麼作了,在新版的IDE和Gradle插件中,會自動地識別所鏈接設備的API level,若是連接的設備API level大於等於21,就會自動打開multindexing,就跟以前設置了dev product的效果同樣。

參考:Enable Android MultiDex

ObsoleteLayoutParam

無用的LayoutParam:當給Widget使用了所在Layout沒有提供的LayouParam時,會有這個提示。這種狀況通常出如今修改Layout類型時沒有同時修改內部Widget的LayoutParam設置或者把一個Widget從一個Layout拷貝到另外一個不一樣類型的Layout內部。

這種無用的LayoutParam在運行時會引發無效的屬性解析,也會誤導閱讀這些代碼的人。因此應該把這些無用的屬性刪除掉。

其餘

WearableBindListener
UseOfBundledGooglePlayServices
相關文章
相關標籤/搜索