公司的項目之前是幾乎是純原生開發,后來因業務需求變更過于頻繁,加上原生開發成本較高,后來采用了混合開發模式,絕大部分頁面采用了H5頁面,因此之前使用的資源文件(包括圖片,xml文件等)大部分被閑置。近段時間,項目成立了專門的優化工作組,清理無用資源,壓縮apk體積也被納入此次優化工作范圍。在做資源清理的時候無可避免的用到了Android-Lint,本文主要講述Android-Lint的使用以及使用中的一些注意事項。
Android-Lint是SDK Tools 16 (ADT 16)之后才引入的工具,通過代碼檢查,可發現潛在的問題,并能對Android程序進行優化處理。在AndroidStudio中已經集成了該工具,下面直接演示使用方法。
如圖,在頂部菜單欄找到Analyze選項,在彈框中選中Inspect Code,或者對項目根雙擊彈出菜單彈框(windows下右鍵項目根目錄),找到Analyze選項再選中Inspect Code選項,可以見到下圖對話框
選中whole project,然后直接選擇OK按鈕,你會見到以下進度條
靜靜地等待,等待時間由你的項目大小和你的機器性能有關,檢查完畢后會彈出Inspection的控制臺
如圖所示,看著你可能會一臉懵逼了(點擊每一項進去還有一大堆子項,你可能會直接暈菜),不過不用急,下面來簡單解釋以下以Android->Lint開頭中一些重的子項的意義,我的初衷是清理無用資源,我用粗體標記了哪些是對此次任務有重要意義的子項。
- Correctness
- DuplicatedIds
Layout中id應該唯一 - NewApi
代碼中使用的某些API高于Manifest中的Min SDK - InconsistentArrays
字符串國際化中,同一名字的的String-Array對應的item值不相同 - Registered
Activity/Service/ContentProvider沒有通過AndroidManifest注冊 - Deprecated
使用已經廢棄的API - PxUsage
避免使用px,使用dp
- Correctness:Messeges
- MissingTranslation
字符串國際化不完全 - ExtraTranslation
國際化的字符串,在默認位置(defaultlocale),沒有定義
- Security
- SetJavaScriptEnabled
不確定你的程序中確實需要JavaScript就不要執行SetJavaScriptEnabled。
2)ExportedContentProvider/ExportedReceiver/ExportedService/ExportedActivity
ContentProvider/Receiver/Service/Activity的exported為true時,設置一個Permission,讓使用者獲取了Permission才能使用。 - HardcodedDebugMode
不要在manifest中設置android:debuggable。
設置它,編譯的任何版本都要采用指定的debug模式。不設置,編譯Eng版本采用debug模式;編譯User版本采用release模式。
***4. Performance ***
**1) DrawAllocation **
**避免在繪制或者解析布局(draw/layout)時分配對象。E.g.,Ondraw()中實例化Paint對象。 ** - ObsoleteLayoutParam
Layout中無用的參數。 - UseCompoundDrawables
可優化的布局:如包含一個Imageview和一個TextView的線性布局,可被采用CompoundDrawable的TextView代替。
**4) UseSparseArrays **
**盡量用Android的SparseArray代替Hashmap ** - DisableBaselineAlignment
如果LinearLayout被用于嵌套的layout空間計算,它的android:baselineAligned屬性應該設置成false,以加速layout計算。 - FloatMath
使用FloatMath代替Math。 - NestedWeights
避免嵌套weight,那將拖累執行效率
***8) UnusedResources/UnusedIds ***
***未被使用的資源會是程序變大,并且編譯速度降低。 *********** - Overdraw
如果為RootView指定一個背景Drawable,會先用Theme的背景繪制一遍,然后才用指定的背景,這就是所謂的“Overdraw”。
可以設置theme的background為null來避免。 - UselessLeaf/UselessParent
View或view的父親沒有用
11)Handler Reference leaks
handler可能導致的內存泄漏
- Usability:Typography
- TypographyDashes
特殊字符需用編碼代替:“–”需要用“–”;“—”需要用“—” - TypographyEllipsis
特殊字符需用編碼代替:“…”需要用“…” - TypographyOther
問題:“(c)”需要用“?”
- Usability:Icons
- IconNoDpi
Icon在nodpi和指定dpi的目錄下都出現。 - GifUsage
Image不要用GIF,最好用PNG,可以用JPG。
- Usability
- BackButton
Android中不要設計有Back的按鈕,Android中一般有Back的硬按鍵。 - ButtonCase
Button的“Ok”/“Cancel”顯示大小寫一定,不要全大寫或全小寫。有標準的資源的字符串,不要自己再定義,而要用系統定義的:@android:string/ok和@android:string/cancel
- Accessibility
- ContentDescription
ImageView和ImageButton應該提供contentDescription
- Internationalization
- HardcodeText
硬編碼的字符串應該在資源里定義 - EnforceUTF8
所有XML資源文件都應該以UTF-8編碼
不必把所有選項的意義都熟稔于心,這些東西網上,下面著重看加粗標記的項目
***UnusedResources ***是我此次代碼檢查的目的,檢測顯示我的項目中有1000多item是未被使用的,選中其中一個xml文件
發現有個Remove All Unused Resources的選項,大喜過望,感覺這項工作so easy,馬上點擊,運行完畢,clean一下,臥槽,報錯,為什么。。。
檢查報錯代碼,發現是內部的安全鍵盤sdk找不到指定id,真是神奇了,不是說好的無用資源嗎?為什么會報錯。突然發現,安全鍵盤對資源文件的調用采用了反射的模式去調用,因為需要它作為一個sdk打包成了jar包,jar包中只包含了它的src中的代碼文件,資源文件也沒有打包,認識直接放到宿主項目的相應文件夾下,使用的時候采用反射的模式進行調用。此時恍然大悟,lint工具會將沒有被直接引用的東西都標記成了無用的。這應該也算是它的一個坑吧。想過先全部清理,然后在把sdk的資源文件放回原位,但是檢查發現還有好幾個早期的內部sdk采用了將資源文件直接放到宿主項目的相應文件夾的做法,難度較大,而且這種隱蔽的東西很難控制,最后只能一個個去刪除,但也只是刪除了一部分,做不到徹底刪除。不過lint工具還是提供了很好的參考。最后將原本將近5M的資源文件刪至3.5M左右,再清理掉一些無用的jar包和so庫,左右將apk的體積壓縮了大概8M左右。
上面還有一個值得注意的地方就是Handler Reference leaks,即是handler可能導致的內存泄漏。可能是項目早期缺乏考慮,加上很多代碼是外包人員編寫,或許是責任心不夠強,項目中使用的handler大部分是內部類,當使用內部類(包括匿名類)來創建Handler的時候,Handler對象會隱式地持有一個外部類對象(通常是一個Activity)的引用(不然你怎么可能通過Handler來操作Activity中的View?)。而Handler通常會伴隨著一個耗時的后臺線程(例如從網絡拉取圖片)一起出現,這個后臺線程在任務執行完畢(例如圖片下載完畢)之后,通過消息機制通知Handler,然后Handler把圖片更新到界面。然而,如果用戶在網絡請求過程中關閉了Activity,正常情況下,Activity不再被使用,它就有可能在GC檢查時被回收掉,但由于這時線程尚未執行完,而該線程持有Handler的引用(不然它怎么發消息給Handler?),這個Handler又持有Activity的引用,就導致該Activity無法被回收(即內存泄露),直到網絡請求結束(例如圖片下載完畢)。另外,如果你執行了Handler的postDelayed()方法,該方法會將你的Handler裝入一個Message,并把這條Message推到MessageQueue中,那么在你設定的delay到達之前,會有一條MessageQueue -> Message -> Handler -> Activity的鏈,導致你的Activity被持有引用而無法被回收。這個問題也是較常見的可能導致內存泄漏的問題,解決方法一般是通過弱引用持有對Activity的引用,具體的實現方式自行百度或者google吧。最后順手點個贊,再順便掃掃碼關注我的公眾號(原諒我的不知足。。。),所有文章都會在公眾號發布。
?
掃一掃或者微信搜索AndroidHouse關注Android小黑屋