Android的ExpandableListView的动画展开效果和使用traceview的性能优化

解决方案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。



郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。