众所周知,微信朋友圈的列表一直以来被众多研究性能问题的朋友拿来做为模范,对于其实现方式,一直以来有点难以望其项背的感受。只能默默的感叹微信的开发者是真的牛逼。通过一段时间的研究,如今我将带领你们以全新的认知对微信朋友圈的结构进行分析,并经过本身的方式加以实现。 先上图:git
GIF看着有点卡,能够下载apk自行体验,流畅度和微信几乎无差异:app-debug.apkgithub
源码地址:HighPerformanceFriendsCircleapi
咱们都知道,在Android中,对于列表的而言,要避免其卡顿,能够从如下几个角度进行优化。数组
一、减小布局层级,避免过多的Item View的无用布局嵌套。 二、对于有图片的列表,要在滑动时对图片加以控制,即滑动时不加载图片,中止滑动以后再加载图片。 三、应当避免在Adapter的填充数据时作过多的计算,或者嵌套过多的逻辑判断。对于复杂的计算结果应当在Adapter填充数据以前计算完成。缓存
以上这些都是针对一个普通的Adapter所基本的一些优化,而对于微信朋友圈这种复杂列表,除了以上几种以外,还须要对其进行其余方面的优化。例如包括减小View的重复建立,构建缓存View,以及减小布局的onMeasure和onLayout次数。这些都尤其重要。下面咱们先简单分析一些微信的列表每一项的视图结构,经过分析微信,咱们能够参悟到一些本身的解决思路。微信
首先咱们经过Android Device Monitor视图分析器来分析微信朋友圈的每个Item的视图结构。 app
在ViewGroup中,有个一方法可能一直被你们所忽略,它就是addViewInLayout(),因为它是protected声明的,因此外部的ViewGroup的子类没法直接调用,而要使用addViewInLayout(),必须继承ViewGroup或ViewGroup的子类并重写该方法。那么addViewInLayout()方法究竟有何用呢?它和咱们经常使用的addView()又有什么区别呢?布局
咱们先来看官方对addViewInLayout()的解释: 性能
简单翻译:在布局中添加视图。 若是在onLayout()方法中,您须要添加更多视图(例如列表视图),这很是有用。 若是索引是负数,则意味着将其放在列表的末尾。优化
这彷佛没什么特殊的,可是它真正的有用的地方在于该方法中的preventRequestLayout
参数,这是一个boolean类型的值,可是它确实及其有用的。若是为true,在添加View时他将不会触发子对象的布局请求。也就是说添加View时不会触发onMeasure和onLayout操做。官方api解释图:
经过对addViewInLayout()的分析,我想你大概明白了,既然动态添加View的时候能够不用触发onMeasure()和onLayout(),那将大量的节约adapter的刷新速度。上面咱们有提到过,对adapter的性能要点中,减小adapter Item的onMeasure和onLayout尤其重要(由于事实上View的显示onMeasure和onLayout须要耗费大量的时间)。
一样的,在移除View时,咱们可使用removeViewInLayout(),它有和addViewInLayout()同样的效果。所以,经过这个办法,咱们解决了评论列表的动态变化更新的性能问题。
而九宫格图片的展现只须要自定义ViewGroup便可实现,其内部依然是对ImageView的添加和移除,一样的咱们可使用该方法addViewInLayout()和removeViewInLayout()来减小onMeasure()和onLayout()的次数以节省性能开支。
其余方面的优化则是尽管在数据Bean中完成对各类数据变换的操做,包括复杂的计算,好比将String转换成须要的SpannableStringBuilder等。
最后就是除了要减小onMeasure()和onLayout()的次数以后,咱们也须要减小View的建立。减小View的建立咱们可使用一个弱引用的缓存数组和实现View对象的缓存,这里要感谢razerdp提供的思路。
具体的一些其余逻辑,代码中自行研究吧,后续可能还会继续更新该项目,包括表情的匹配,电话号码的匹配等,看本身时间状况。欢迎你们start!
昨天有一位网友提出了一个问题,后面通过分析,发如今adapter中使用addViewInLayout()和addView()去添加一个或多个View无异,也就是说在adapter中构建评论数据时使用addViewInLayout()并不会减小onMeasure()和onLayout()的次数,缘由后续再单独出一篇文章进行说明,这里感谢@Caij的指正!