Android性能优化-ListView自适应性能问题( 三 )


Android性能优化-ListView自适应性能问题

文章插图
NoScrollListview 出现的主要目的是为了支持ListView放在ScrollView等垂直滚动视图中,原理很简单,利用前面ListView测量原理分析到的机制,强行设置AT_MOST来测量子View高度,也就是强制ListView自适应,即使你在xml中正确地使用layout_height=”match_parent”,在JAVA代码里面也会强行设置成wrap_content,导致的结果就是每一次onMeasure都会不停调用getView 。
如果,结合上前面说的RelativeLayout嵌套,ListView的性能损耗还要再翻倍!
假设ScrollView中存在RelativeLayout里面嵌套NoScrollListview,RelativeLayout嵌套层数为n,那么onMeasure的次数为2^n+2^(n+1)次,ListView显示项数为m,getView调用次数为(2^n + 2^(n+1) +1)* m次 。如果n=4,m=10,getView次数为490次
Android性能优化-ListView自适应性能问题

文章插图
相信看到这里,终于知道为什么ScrollView中嵌有列表的页面会卡出翔了吧!
当然,事情还远远不止这么简单,尤其在某些特殊的场景下,容易导致onMeasure频繁调用,以实际项目中遇到的问题场景举两个例子 。
  1. 有些ScrollView具有下拉弹性功能,当手指下拉时会导致子View不停onMeasure,如果子View包含NoScrollListview,页面肯定一顿一顿的 。
  2. 如果你在getView中的某些不恰当的操作导致ListView重新onMeasure,比如setVisibility为Gone等,就会造成onMeasure和getView的相互循环调用,这时候性能消耗非常严重(一般不会ANR) 。
  3. 同样的,某些时候我们需要监听ListView的滚动状态,会使用setOnScrollListener,由于在onMeasure的时候会触发OnScrollListener的回调,如果回调里面某些不恰当的操作导致ListView再次触发onMeasure就会导致OnScrollChangeListener和onMeasure两者的死循环 。
5 心得建议
对于以上几点问题,有如下一些建议:
 
  1. 使用ListView的时候注意尽量使用layout_height=”match_parent” 。
  2. 如果第1点无法避免,需要注意ListView的父布局,父布局以上绝对不要使用RelativeLayout,即使使用FrameLayout或LinearLayout会增加布局层级 。
  3. 如果第1点无法避免,需要注意不要在getView中使用setVisibility这种会触发ListView重新onMeasure的操作 。
  4. 如果ListView存在位移,比如下来刷新等,绝对要遵循第1点来设置layout_height=”match_parent”,不然频繁触发onMeasure会导致交互卡顿 。
  5. 关于NoScrollListView,这种布局是严禁使用的,无论是哪种场景,如果ScrollView中必须要使用ListView,可以使用SimulateListView控件代替ListView

【Android性能优化-ListView自适应性能问题】


推荐阅读