遇到一個從快播出來的Android開發,有11年的開發經驗,咋一看不管是資歷還是經歷都挺嚇人的。但和他共處一段時間后,發現他完全沒有體現出11年工作經驗的優勢,相反還常常犯一些低級的錯誤,如在ListView中加載本地的圖片(大圖)時不使用異步線程,而是直接setImageResource。而他工作和為人都很努力,對分配的工作都很認真,但效果卻常常不盡如人意,不管是和Android特性相關的代碼還是純邏輯的代碼,他都常常犯一些低級的錯誤(這些錯誤都是普遍認為一個11年工作經驗的人不應該犯的)。
后來我經常思考,是什么樣的原因導致一個人的工作年限和水平并不能成正比。我想到有兩個方面:
- 看待問題的眼界過窄,只能看到當前的可見的問題。(或者說他思考問題的角度和方式有較大的局限)
- 技術的要點沒有掌握,常常找不到合理的解決問題的方案。
這兩點都是需要慢慢地提升和積累,當一個人長時間在思維和眼界上沒有進步,技術也只懂些皮毛(或者只是會用),那么他工作越長時間他的優勢反而越不明顯,甚至變成劣勢。
面試題:如何優化ListView的性能?
在回答這個問題前,我認為很有必要和大家講幾點和getView相關的問題。我們設置或者優化ListView的性能很多時候都是在getView中完成的,反過來說就是很多性能問題都是由于沒有正確使用getView造成的。
public View getView(int position, View convertView, ViewGroup parent)
所以我們不妨先思考一下如下的幾個問題:
在一次顯示ListView的界面時,getView會被執行幾次?
每次getView執行時間應該控制在多少毫秒之內?
getView中設置listener要注意什么?
首先我們要知道ListView的ItemView有一個復用機制,簡單看如下圖所示,ListView中有一個RecycleBin類復負回收不可見且可能被再次使用的ItemView,由ScrapView存儲。
所以我在們設置Listener進就要注意,使用convertView時需要重新設置一個Listener,保括一些數據也需要重設置,不然可能會顯示之前那個ItemView在回收前的狀態。
在繪制ListView前往往要計算它的高度,所以一個ListView界面上可以看到6個ItemView,但是getView的執行次數卻有可能是12次,多出的次數用來計算高度(這個可以通過設置ListView的height為0來避免)。所以要避免在getView中進行邏輯運算,兩次計算同一邏輯完全是浪費。
每個getView的執行時間更是少得可憐,很多人可能對這個時間沒有概念,我可以簡單的給大算一下:
1秒之內屏幕可以完成30幀的繪制,人才能看到它比較流暢(蘋果是接近60幀,高于60之后人眼也無法分辨)。
每幀可使用的時間:1000ms/30 = 33.33 ms
每個ListView一般要顯示6個ListItem,加上1個重用convertView:33.33ms/7 = 4.76ms
即是說,每個getView要在4.76ms內完成工作才會較流暢,但是事實上,每個getView間的調用也會有一定的間隔(有可能是由于handler在處理別的消息),UI的handler處理不好的話,這個間隔也可難會很大(0ms-200ms)。結論就是,留給getView使用的時間應該在4ms之內,如果不能控制在這之內的話,ListView的滑動就會有卡頓的現象。
了解了這幾個問題,現在我們回來這次主要考查的面試題上,如何進行ListView的性能優化,讓它滑動更加流暢。大家一般常用如下方法:
- 重用ConvertView;
- 使用View Holder模式;
- 使用異步線程加載圖片(一般都是直接使用圖片庫加載,如Glide, Picasso);
我認為這些是面試者必備的知識點,如果連這些都說不清楚的話,也沒有必要再深入問了。針對面試者的回答,可以適當選一兩點追問一下,看是否真正明白。如:ViewHolder為什么能夠起到優化性能的作用?
除此之前還有一些優化建議:
- 在adapter的getView方法中盡可能的減少邏輯判斷,特別是耗時的判斷;
- 避免GC(可以從LOGCAT查看有無GC的LOG);
- 在快速滑動時不要加載圖片;
- 將ListView的scrollingCache和animateCache這兩個屬性設置為false(默認是true);
- 盡可能減少List Item的Layout層次(如可以使用RelativeLayout替換LinearLayout,或使用自定的View代替組合嵌套使用的Layout);
關于第4點,發現在一些型號的手機(如華為的P7)上特別管用,當其也優化都做完之后,有無這兩項設置滑動的卡頓情況有明顯不同。
<Listview
android:scrollingCache="false"
android:animationCache="false"
小結
關于ListView有很多方面可以考察面試者,因為它實在是用的太頻繁了,雙方都能對某個問題點進行展開。如果一個面試者都沒有做過ListView優化,那么如果不是他寫的代碼太少就是他使用ListView加載的數據太簡單(可能只有幾十項),其本上沒有其他選項。所以這一題是很能看出面試者的項目經驗和實際的開發水平,屬于面試必考題之一。