写点什么

华为手机刷微博体验更好?技术角度的分析和思考,字节跳动算法工程师总结

用户头像
Android架构
关注
发布于: 16 小时前
  1. 反编译的微博版本:10.8.1

3 结论先行

‘’微博这个 App 在华为的手机上,在主页列表上下滑动的情况下依然可以流畅加载图片 ‘’这个现象是因为华为和微博做了联合优化,主要是为了优化微博列表滑动时候的用户体验,其优化点如下


  1. 华为提供了一个简单的接口打包成 SDK 提供给微博,这个接口可以让微博的列表监听到列表的当前速度(Velocity),在速度高于阈值或者低于阈值的时候,都会及时通知 App

  2. 微博拿到这个速度回调之后,就可以根据列表的滑动速度来决定是否要在滑动过程中加载图片,一旦列表的滑动速度低于设定的阈值,就开启图片加载;一旦列表的滑动速度高于设定的阈值,就关闭图片加载

  3. 华为检测到这个应用使用了 SDK,就可以将优化过后的滑动曲线应用在这个 App 的列表 Fling 阶段,提升用户体验


对细节感兴趣的同学可以继续阅读,有能力的同学看完后可以修改 Framework 相关代码,编译一个 SDK,然后自己写个 Demo 接入 SDK,就可以打通我下面所说的所有内容了,我自己在 AOSP 的代码上实现了一遍,Demo 也可以正常运行,有兴趣可以跟我私下交流。

4 微博+华为是怎么优化?

现象分析

我们在滑动微博列表的时候,一个滑动操作主要由下面三部分组成


  1. 手指接触屏幕,上下滑动微博主页列表,但是手指 没有离开屏幕 ,这个阶段我们称之为阶段一,技术术语为 SCROLL_STATE_TOUCH_SCROLL

  2. 手指上下滑动的时候 离开屏幕 (必须有一个上滑或者下滑的速度),微博列表有了一个惯性,根据惯性的方向继续滑动,这个阶段我们称之为阶段二,技术术语为 SCROLL_STATE_FLING

  3. 列表惯性滑动后停止,这 个 阶段我们称之为阶段三 , 技术术语为 ?SCROLL_STATE_I DLE


而华为和微博的优化主要在阶段一和阶段二。

阶段一优化

  1. 优化前:只要手指不离开屏幕,图片加载功能关闭

  2. 优化后:只要手指不离开屏幕,列表就不会滑动太快,这时候图片加载功能开启

阶段二优化

  1. 滑动图片加载优化

  2. 列表滑动速度太快,这时候图片加载功能关闭

  3. 列表滑动速度掉落到一个阈值,图片加载功能开启

  4. 优化前:只要列表滑动不停止,图片加载功能关闭

  5. 优化后:图片加载功能是否开启取决于当前列表滑动的速度

  6. 列表 Fling 曲线优化

  7. 优化前:列表滑动的曲线是默认值,滑动时间比较短,停止的时候比较突兀,不柔和

  8. 优化后:列表滑动的曲线是华为经过优化的,滑动时间比较长,停止的时候比较柔,不突兀,比较接近 iPhone 的列表滑动曲线

技术分析

技术分析的代码主要来源于微博 apk 的反编译,微博版本 10.8.1,通过反编译的代码可以看到, 微博主页在初始化的时候,会接入华为提供的 PerfSDK,从而获得监听列表滑动速度的能力。

阶段一优化的技术分析

列表的 ScrollStateChange 是标识列表状态的一个回调,微博在 ScrollStateChange 这个回调中会根据当前的状态来决定是否加载图片, 从下面的代码逻辑来看:


  1. 当 滑动图片加载优化生效 的时候,如果 State != 2,那么就允许 ImageLoader 加载图片,State?为 2 也就是 SCROLL_STATE_FLING,熟悉列表滑动的同学应该知道,SCROLL_STATE_FLING? 就是 滑动列表的时候手指松手后列表继续滑动的那一段 ,叫 fling,毕竟只有 fling 的时候才有 Velocity,松手后会根据这个值的大小计算滑动曲线和滑动时长

  2. 当 滑动图片加载优化不生效 的时候,就到了常规的列表滑动优化:即列表停止之后才开始加载图片 :State !=0,0 即 SCROLL_STATE_IDLE


阶段二优化的技术分析

微博的主页在初始化的时候,会给首页的 ListView 注册一个 HwPerfVelocityCallback,从名字可以看出来,这个回调是监听 Velocity 的,也就是滑动的速度,两个回调:


  1. HwPerfonVelocityDownToThreshold : 当速度降低到阈值之后,打开 ImageLoader 的图片加载功能

  2. HwPerfonVelocityUpToThreshold:当速度升高到阈值之后,关闭 ImageLoader 的图片加载功能


下图为反编译后的源码



至于滑动曲线,则需要查看华为的 Framework 的代码,由于代码量比较大,这里只贴一下 OverScroller.java 中的 update 方法,具体感兴趣的可以自己去翻一番华为的 Framework 代码:



计算 Distance 的代码



计算 Velocity 的代码



关于滑动曲线的解释,大家可以看这一篇知乎回答,其中对比了 iOS 和 Android 的滑动曲线的不同 :为什么 iOS 的过渡动画看起来很舒服?https://www.zhihu.com/question/291779390/answer/484881732

其他厂商处理

上面图中代码最后一段还有一个判断开关, 如果 boolean a = HwPerfUtil.m14290a 这个返回的是 false,这就是说有可能华为这个优化关闭了,有可能是非华为机器,那么会 判断 Android 版本号和全局 Feature 开关:



对应的 FeedAbManager 就是一个 Feature 管理器,可以在线开关某些 Feature



而 m52580k 的实现如下



可以看到这里还受到一个全局的 Feature 配置:feed_scroll_loadimage_enable,这个 Feature 是服务端可以配置的



这里就是处理其他厂商的逻辑。

最后一个问题:滑动点击

滑动点击是个什么问题呢?列表在滑动的过程中,如果用户点击列表的某一个 Item,那么根据 Android 的事件分发机制,这时候列表的 Item 并不会被点击到,而是整个列表先收到点击事件,然后 触发列表滑动停止;列表停止的时候点击 Item 才会触发 Item 的点击。上面阶段二的优化中,**在优化了滑动曲线之后,列表处于 Fling 状态的时间变长,如果用户想点击去某一个 Item 查看详情,那么需要先点击一下让列表停止,然后再点击一下才能进去,这就是这一节想说的 :滑动点击问题。**滑动(Fling 状态)和点击其实是需要一个平衡的,这个平衡需要开发者自己去把控:滑动(Fling 状态)的时间越短,列表越容易停下,用户点击列表越容易触发 Item 的点击,但是容易停止带来的问题就是不够柔和。想象你在粗糙的水泥地上滑出去一块石头,这石头没有滑动多久就会停止,不管是扔石头的你还是旁边看你扔石头的我,都不会觉得这有什么美感,但是没得选。这个的 代表其实就是 Android 原生的 Fling 曲线。滑动(Fling 状态)的时间越长,滑动(Fling 状态)的时间越长,列表越不容易停下,用户点击列表越不容易触发 Item 的点击,如果曲线优化的好,给人的感觉就是很柔和,符合物理规律,想象你在光滑的冰面上滑出去一块冰,


《Android学习笔记总结+最新移动架构视频+大厂安卓面试真题+项目实战源码讲义》
浏览器打开:qq.cn.hn/FTe 免费领取
复制代码


冰面越滑,冰块滑动的时间就越长,越不容易停下。这其中的极端代表就是 iOS 的 Fling 曲线。说 iOS 极端是因为,iOS 的滑动曲线调的太磨叽了,时间长不说,停的异常慢,很多时候你都需要点击一下列表让他先停止,然后再进行下一步的点击动作。而小米的 MIUI12 对这个也进行了调整,效果要比 iOS 好一些,如果再和三方进行类似华为和微博的合作,体验会更上一层楼。滑动点击问题其实也可以通过厂商和 App 合作来解决,比如,当滑动到整个滑动距离的 98%(或者 95%) 之后,用户点击列表不再是让列表停止,而是列表内的 item 响应这个点击。这个思想来源于 Launcher 的代码,Launcher 的每一页在左右滑动的时候,如果滑动还没有停止但是用户比较手速快点击了某个 icon 想启动,那么这时候不会触发 Page 停止,而是直接响应 icon 的点击启动应用操作。5 延伸阅读

列表滑动图片加载的性能考虑

前文有提到这个问题,滑动的时候进行图片加载主要有两个问题:


  1. 如果用户滑动非常快,比如是想找昨天发的某个微博,那么今天发的所有的带图片的微博在用户滑动的时候是没必要加载的,因为用户的目标不是这些图片,而 App 去加载这些图片,而程序员是不会为用户提前加载你未看到的数据,因为加载过多的数据不仅容易发生数据复用、缓存过多、内存溢出等错误,还会对服务器造成不必要的资源请求。

  2. 如果用户滑动非常快,那么图片加载队列势必有许多无效的资源(对这一刻的用户来说),而用户真正想看的图片反而排在了加载队列后面,造成加载速度变慢,也会影响用户的体验


滑动中加载图片最大的风险其实就是造成卡顿,因为图片加载本身就是一个比较重的操作,而高帧率的手机上,一帧的时间被压缩到很短,任何小的不确定性都有可能造成卡顿。所以厂商+应用的这个优化:快速滑动不加载图片,慢速的时候再加载,然后优化滑动曲线?,其实对厂商和应用都是非常有益处的、

列表滑动监听背景知识

下面的 AbsListView 的 OnScrollListener 里面标注了列表滑动的三个状态


  1. 滑动停止:SCROLL_STATE_IDLE

  2. 手指在屏幕上滑动:SCROLL_STATE_TOUCH_SCROLL

  3. 手指离开屏幕,列表靠惯性继续滑动:SCROLL_STATE_FLING


两个回调


  1. 列表状态变化时的回调 :onScrollStateChanged

  2. 列表滑动时候的回调:onScroll


public interface OnScrollListener {


// The view is not scrolling. Note navigating the list using the trackball counts as being in the idle state since these transitions are not animated.public static int SCROLL_STATE_IDLE = 0;


//The user is scrolling using touch, and their finger is still on the screenpublic static int SCROLL_STATE_TOUCH_SCROLL = 1;


//The user had previously been scrolling using touch and had performed a fling. The animation is now coasting to a stoppublic static int SCROLL_STATE_FLING = 2;


// Callback method to be invoked while the list view or grid view is being scrolled. If the view is being scrolled, this method will be called before the next frame of the scroll is rendered. In particular, it will be called before any calls topublic void onScrollStateChanged(AbsListView view, int scrollState);


// Callback method to be invoked when the list or grid has been scrolled. This will be called after the scroll has completedpublic void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount);}

用户头像

Android架构

关注

还未添加个人签名 2021.10.31 加入

还未添加个人简介

评论

发布
暂无评论
华为手机刷微博体验更好?技术角度的分析和思考,字节跳动算法工程师总结