安卓下拉刷新开源库对比

来源:互联网 发布:网络导购员是做什么的 编辑:程序博客网 时间:2024/06/10 21:22

安卓下拉刷新开源库对比

450人阅读 评论(0)收藏举报
本文章已收录于:
分类:
作者同类文章X

    目录(?)[+]

    1. Repo
    2. 拓展性
    3. 易用性
    4. 性能分析
      1. 1 Chris Baness Ptr
      2. 2 liaohuqius Ptr
      3. 3 johannilssons Ptr
      4. 4 Yalantiss Ptr
      5. 5 race604s Ptr
      6. 6 SwipeRefreshLayout
    5. 总结
    6. 附录-知识点参考

    目前仅比对github上star数>1500的下拉刷新开源库,在比较完成之后可能会加入其它有代表性的库.

    Repo

    RepoOwnerStar
    (2015.12.5)versionSnap shotAndroid-PullToRefresh
    (作者已停止维护)chrisbanes6014latestchrisbanesandroid-Ultra-Pull-To-Refreshliaohuqiu34131.0.11liaohuqiuandroid-pulltorefresh
    (作者已停止维护)johannilsson2414latestjohannilssonPhoenixYalantis18971.2.3yalantisFlyRefreshrace60418432.0.0flyrefreshSwipeRefreshLayoutAndroid 
    Support v4 
    (19.1.0 ↑)Nonelatestswipe_refresh

    拓展性

    Repo自定义顶部视图支持的内容布局Android-PullToRefresh不支持,只能改代码。
    由于仅支持其中实现的LoadingLayout作为顶视图,改代码实现自定义工作量较大。任意视图,内置:GridView
    ListView,HorizontalScrollView
    ScrollView ,WebViewandroid-Ultra-Pull-To-Refresh任意视图。
    通过继承PtrUIHandler并调用
    PtrFrameLayout.addPtrUIHandler()得到最大支持。任意视图android-pulltorefresh不支持,只能改代码。
    代码仅一个ListView,耦合度太高,改动工作量较大。无法扩展,自身为ListViewPhoenix不支持,此控件特点就是顶部视图及动画。任意视图,只显示最后一个嵌套的子视图。FlyRefresh不支持,此控件特点就是顶部视图及动画。任意视图SwipeRefreshLayout不支持,固定为Material风格任意视图

    易用性

    Repo可在gradle配置上拉加载自动加载滑动阻尼配置Android-PullToRefresh×√×移动比固定1/2android-Ultra-Pull-To-Refresh√×√√android-pulltorefresh×××移动比固定1/1.7Phoenix√××移动比固定1/2FlyRefresh√×××SwipeRefreshLayout√××移动比固定1/2

    性能分析

    通过捕捉如下图中的操作持续1秒钟的systrace进行性能分析:

    trace_operation

    注:由于开源库Header大多无法直接放自定义顶部视图,头部视图复杂程度不同,数据对比结果会有所偏差。

    1. Chris Banes's Ptr

    滑动实现方式:触摸造成的下拉均是View.scrollTo()实现的;在松手之后,View.post(Runnable)触发Runnable执行回滚动画,在滑回原处之前不断post自己,并配合Interpolator执行scrollTo()进行滚动。

    trace snapshot:

    trace_chrisbanes

    分析

    作为Github上星星数最多的Android下拉刷新控件,从性能上看(渲染时间构成)几乎没有什么明显的缺点。可惜的是作者已经不再维护,顶部视图的扩展性比较差,并且gradle中也无法使用。在本次demo这类层级比较简单的环境中,几乎都达到了60fps,可以与后面的trace对比。

    2. liaohuqiu's Ptr

    滑动实现方式:触摸造成的下拉均是View.offsetTopAndBottom()实现的;在松手之后,触发Scroller.startScroll()计算回滚,使用View.post(Runnable)不停地监视Scroller的计算结果,从而实现视图变化(此处依然是View.offsetTopAndBottom()完成视图移动)。

    trace snapshot:

    trace_liaohuqiu

    分析

    这套开源库可以说是自定义功能最强的组件了,你可以实现PtrUIHandler并将其add到PtrFrameLayout完美地与下拉刷新事件适配。美中不足的就是在下拉状态变化的时候会有一阵measure时间。我查看了一下代码,发现是PtrClassicFrameLayout的顶部视图出了问题:

    liaohuqiu_header

    看!都是wrap_content,那么当里面的内容变化的时候,是会触发View.requestLayout()的。不要小看这一个子视图的小操作,一个requestLayout()大概是这么一个流程:View.requestLayout()->ViewParent.requestLayout()->...->ViewRootImpl.requestLayout()->ViewRootImpl.doTraversal()=>MEASURE(ViewGroup)=>MEASURE(ChildView of ViewGroup)

    在层级复杂的时候(大部分互联网产品由于复杂的产品需求嵌套都会比较多),它会层层向上调用,将measure时间放大至一个可观的层级。下拉刷新界面的卡顿由此而来。

    我修改了一下,将其全部变为固定高度、宽度,之后的trace如下:

    trace_liaohuqiu_new

    measure时间神奇的没掉了吧:)

    3. johannilsson's Ptr

    滑动实现方式:初始时setSelection(1)隐藏顶部视图(使用这个下拉刷新控件注意将滚动栏隐藏,否则会露馅)。在拉下来超过header view的measure高度之前,均是ListView自有的滚动;在下拉超过header measure高度之后,对header使用View.setPadding()让header继续下移。

    trace snapshot:

    trace_johan

    分析

    通过顶视图调用View.setPadding()来实现的滑动,在下拉距离超过header高度后,会造成不断的requestLayout()!这就解释了为什么图中UI线程的蓝色块时间(measure时间)很明显。当你在视图层级比较复杂的app中使用它时,下拉动作所造成的开销会非常明显,卡顿是必然结果。

    4. Yalantis's Ptr

    滑动实现方式:通过View.topAndBottomOffset()移动视图,在松手之后启动一个Animation执行回滚动画,内容视图的移动也使用View.offsetTopAndBottom()实现。为了保证内容视图的padding在移动视图之后与布局文件中的padding一致,它额外调用了View.setPadding()实时计算与设置padding。

    顶部动效实现方式:Drawabledraw()中,为Canvas中设置“太阳”偏移量及背景缩放。

    trace snapshot:

    trace_yalantis

    分析

    此开源库动画效果非常柔和,且顶部视图全部是通过draw去更新,不会造成第三个开源库那样的大开销问题。可惜的是比较难以去自定义顶部视图,不好在线上产品中使用,不过这个开源库是一个好的练手与学习的对象。由于顶部动效实现开销不大,它的性能同样非常好。

    它的在松手后回滚动画时调用的View.setPadding()可能会造成measure开销比较大,于是我特地测了一下松手回滚的trace,一看确实measure时间非常可观:

    trace_yalantis_scroll_back

    确实它如果要保证展示内容视图的padding与布局文件中一致,是必须这么做的(调用View.setPadding()),因为通过View.offsetTopAndBottom()向下移动视图会影响底部的padding。但是很有意思,它向下移动的时候没有这么设置,拉下来的时候底部padding就没了。回滚动画的时候才设了padding,就显得没那么必要了。我在demo中也进行了实践,确实是这样的:

    yalantis_padding

    实际上,由于这个库是一个嵌套视图,可以尝试在父视图的onLayout中进行处理由于位置变化带来的padding影响,这么处理,只是在layout阶段处理,不会造成measure的大量开销。

    我粗略的做了一点点改动,只在父视图中处理padding而不是在子视图里面做,就可以在上拉、下拉的时候保持padding不变,并且性能有了很大提高。不过好像逻辑就有点问题,还需要再做改动,已经跟作者提出issue。

    改动后松手回滚trace,已经没有了measure时间:

    yalantis_back_trace_new

    改动后的样子,上下拉动时padding不会变动。不过每次回滚的时候顶部会多往里面滚一点,还需作者针对issue完善:

    yalantis_padding_new

    5. race604's Ptr

    滑动实现方式:View.topAndBottomOffset()

    顶部动效实现方式:

    • 飞机滑动 ObjectAnimator.
    • 山体移动、树木弯曲 通过移动距离计算山体偏移、树木轮廓,得出Path后进行draw.

    trace snapshot:

    trace_flyrefresh

    分析:每次拖动都会重新计算背景"山体"与"树木"的Path,造成了draw时间过长。效果不错,也是一个好的学习对象,相比Yalantis的下拉刷新性能上就差一些了,它的draw中的计算量太多。使用起来疑似有bug:拖动到顶部,无法再往上拖动,并且会出现拖动异常。

    6. SwipeRefreshLayout

    滑动实现方式:内容固定,仅有顶部动效。

    顶部动效实现方式:

    • 上下移动 View.bringToFront() + View.offsetTopAndBottom().
    • 动效 通过移动偏移量计算弧形曲线的角度、三角形的位置,使用drawArcdrawTriangle将他们画到Canvas上。

    trace snapshot:

    trace_swipe

    分析:官方的下拉刷新组件,动画十分美观简洁,API构造清晰明了。但是为什么每次的移动都会有一段明显的measure时间呢?我研究了一下代码,发现罪魁祸首是View.bringToFront(),它在每一次滑动的时候都会对顶部动效视图调用这个函数。仔细追朔这个函数源码,它会走到下面这段代码中:

    ViewGroup.Java

     public void bringChildToFront(View child) {        final int index = indexOfChild(child);        if (index >= 0) {            removeFromArray(index);            addInArray(child, mChildrenCount);            child.mParent = this;            requestLayout();            invalidate();        }    } 

    看,它是会触发View.requestLayout()的!这个函数会造成的后果我们在之前已经解释了,它会造成大量的UI线程开销。实际上我认为这个函数是没有调用的必要的,SwipeRefreshLayout明明在重写onLayout()的时候,header会被layout到child之上,没有必要再bringToFront()

    于是我copy了一份代码,将这一行注了(对应代码ptr-source-lib/src/main/java/com/android /support/SwipeRefreshLayout.java),再次编译,measure时间确实没掉了,对功能毫无影响,性能却有了很大优化:

    trace_swipe

    这样一来就不会每一次拉动,都会触发measure。若有同学知道这个bringToFront()在其中有其他我未探测到的功效,请issue指点:)

    总结

    Repo性能拓展性综合建议Android-PullToRefresh★★★★★★★★由于作者不再维护,无法在gradle中配置,顶部视图难以拓展,不建议放入工程中使用android-Ultra-Pull-To-Refresh★★★★★★★★★★如之前分析,PtrClassicFrameLayout性能有缺陷;建议使用PtrFrameLayout,性能较好。这套库自定义能力很强,建议使用。android-pulltorefresh★★实现方式上有缺陷,拓展性也很差。优点就是代码非常简单,只能作为反面例子。Phoenix★★★★★★效果非常好,性能不错,可惜比较难拓展顶部视图,为了适配布局padding造成了性能损失,有优化空间。可以作为学习与练手的对象。FlyRefresh★★★★★★效果很新颖,可惜的是顶部视图计算动效上开销太大,优化空间较少,可以作为学习与练手的对象。SwipeRefreshLayout★★★★★官方出品,更新有保障,但是如上分析,其实性能上还是有点缺陷的,拓展性比较差,不建议放入工程中使用。

    附录-知识点参考

    1. 为你的应用加速 - 安卓优化指南
    2. 使用Systrace分析UI性能
    3. Systrace-文档
    来自:https://github.com/desmond1121/Android-Ptr-Comparison
     
    0
    0
     
     

    我的同类文章

    http://blog.csdn.net
    • 自定义一个类似listView和recylceView的需要setAdapter的控件2017-03-14
    • 一个反编译看代码的途径和android6.0权限控制实例2017-01-06
    • Android6.0动态权限申请步骤以及需要注意的一些坑2016-12-17
    • java算法之归并排序2016-12-07
    • java算法之插入排序2016-12-06
    • java算法之链表2016-12-06
    • 【Android学习笔记】RecycleView 绑定了Adapter的item明明设置了match_parent却不起作用2017-03-09
    • Retrofit简单使用手册2016-12-24
    • AsyncTask的cancel方法并没有停止任务2016-12-15
    • java算法之选择排序2016-12-06
    • java算法之冒泡排序2016-12-06
    更多文章
    0 0
    原创粉丝点击
    热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 车辆年审超时间怎么办 车辆过年检了怎么办 开公司货车违章怎么办 毕业证丢了怎么办居住证 贴吧回帖被秒删怎么办 群拉人失败了怎么办 安装解释包错误怎么办 皮皮麻将进不去怎么办 郑州集体户口怎么办准生证 广州集体户口准生证怎么办 学校寄档案丢失怎么办 深圳通儿童卡怎么办 集体户没有户口卡怎么办 北京滴滴跑长途怎么办 应届毕业生落户成都档案怎么办 执业医师缺考怎么办 国家级考试缺考怎么办 异地就业后档案怎么办 没有工作报到证怎么办 网络系统管理员封锁网络怎么办 公房没买断产权怎么办 去异地工作社保怎么办 深圳辞职了 社保怎么办 小产权孩子上学怎么办 多余的粽叶怎么办 农村两处宅基地怎么办 农村一户多宅怎么办 无锡未满五年安置房怎么办 人才公寓退休后怎么办 套餐到期不用了怎么办 日本手机自动续约怎么办 如果购房后退房怎么办 土地权70年到期怎么办 在亚庇丢了护照怎么办 回国丢了护照怎么办 大学挂科拿不到毕业证怎么办 孩子脸上长黑痣怎么办 婴儿tsh10.6偏高怎么办 苹果x显示edge怎么办 煮的鸡肉腥怎么办 卫生间蹲坑太高怎么办