Android的ExpandableListView的動畫展開效果和使用traceview的效能最佳化,androidtraceview
解決方案Github pull request連結:https://github.com/idunnololz/AnimatedExpandableListView/pull/30
Android的原生提供和展開分組的ListView:ExpandableListView,然而相比於iOS上原生提供的UITableView,其UI能力不足,比如沒有原生的動畫展開和收合效果支援。
在開原始碼社區我們可以找到幾個為Android的ExpandableListView添加的動畫解決方案。其中idunnololz的AnimatedExpandableListView是不錯的方案之一。
(https://github.com/idunnololz/AnimatedExpandableListView)。它的優點:效能較好,提供原始碼而不是library(這點很重要),注釋清晰。
然而效能的最佳化是沒有止境的,當分組內的子view(childView)變得複雜,或者ListView的parent結構複雜,例如內嵌與其它LinearLayout, FrameLayout或者ScrollView之中,並且parent的使用自訂的重寫的onMeasure()方法時,產生childView的效率就會大大影響應用的效能。
合理使用AnimatedExpandableListView的關鍵是在於AnimatedExpandableListView#getRealChildView()的實現,這是應用開發的責任。實際項目中,通過最佳化getRealChildView(),動畫效果的啟動時間從1340ms減少到了680ms (展開一個含有5個子項目的分組)。而發現的問題的定位和解決方案,基本是用過使用Android提供的method tracing方法(android.os.Debug.startMethodTraceing)進行分析。
最佳化前的getRealChildView()實現,需要大量的view初始化,因為沒有可用的convertView,而事實上,在動畫繪製階段時產生的childView完全可以被重用,及時convertView並為給出。如下面的traceview profile看到的,最佳化前,getChildView()消耗了超過一秒的時間。
最佳化後的效能:
這是如何做到的呢?這需要我們再研究一下動畫展開的原理,也就是getChildView()裡面耗時最長的是哪些動作。首先排除其他因素的影響,專註於AnimatedExpandableList本收得使用,我們使用GitHub上原生提供的Example來做分析:這是展開5個子項目的分組的情況,注意5個子分組的view產生,LayoutInflater.inflate被執行了10次,是其兩倍。而inflate是相當耗時的。有沒有方法來減少這部分工作消耗呢?
方法是使用Android推薦的LRU cache來儲存childView的。關於LruCache,請見Android的reference documents和training。這裡特別要注意的是,childView在dataSet改變時需要重建,而不是在cache中獲得,這裡使用的方法是判斷childView的type。在自己的項目中需要根據情況認真考慮dataSet改變如何更新cache的問題。效果如下所示:inflate的次數減少到5次,一次都不浪費。消耗時間從160ms降低到80ms。
寫一個ExpandableListView實現點擊效果
配置 listSector
android的ExpandableListView
xml:
android:cacheColorHint="#00000000"
java code:
listView.setCacheColorHint(0x00000000)