前情描述:

最近接到一个首页图片加载优化的任务,图片是展示在首页RecyclerView中。问题现象是即使有缓存,图片的展示还是会肉眼可见的跳变,没法做到一打开首页,图片就展示在那。

问题定位:

RecyclerView中的图片是在onBindViewHolder方法中,使用glide加载的网络图片,使用了glide的缓存。为了让图片频繁刷新不闪烁,我们采用了使用glide加载成bitmap,再将bitmap设置到ImageView中的方案。在各行代码上增加了日志输出定位耗时的时候,发现网络图片glide进行了缓存,加载缓存耗时其实极短,真正的耗时在于应用启动后,主线程忙碌,glide子线程加载完bitmap后,转主线程设置到ImageView中这一操作由于主线程忙碌被阻塞了。

解决方案:

这时一个骚操作的想法突然出现在我的脑海,将bitmap设置到ImageView的操作扔到子线程中去操作。说到这里,可能会有一些同学会很诧异,UI操作怎么可以扔到子线程中呢?不会抛出异常么?

我们重新来审视一下那条错误提示,“Only the original thread that created a view hierarchy can touch its views.”,这条错误信息里也没有说是只有主线程才能处理ui操作,说的是只有创建了那个View的线程才可以操作这个view,所以假如你是一个独立的拥有窗口(Window)展示的View,其UI线程可以独立于App主线程(这个方案和原理详解可以参见:Android 子线程 UI 操作真的不可以?)。

但是我们这里的情况肯定不适用于这个方案,那么还有没有其他的情况可以绕过这个线程检查呢?上述异常抛出的地方是ViewRootImpl里的checkThread方法,这个方法基本会在所有的view更新方法中调用,用以防止多线程的UI操作,但是,如果一个View还没有关联的ViewRootImpl对象时,就不会触发checkThread方法,也不会抛出异常。

查看ImageView的调用链,在requestLayout里,会触发checkThread,但是如果没有ViewRootImpl的话,就不会触发,不会抛出异常。ViewRootImpl是啥时候赋值的呢?

mAttachInfo是在View被attach的时候赋值的,在detach的时候赋空的。源码如下:

回到我们的情况上来,所以要在子线程进行UI操作,所以就需要在holder被attach上之前完成图片的加载和设置。RecyclerView的Adapter里,ViewHolder是什么时候完成attach的呢?Adapter里有一个方法叫onViewAttachedToWindow,会在View被attach的时候调用,重写这个方法,我们会发现,Adapter会先调用onBindViewHolder,然后调用onViewAttachedToWindow,所以我们可以在onBindViewHolder的实现中尝试使用子线程进行UI操作。不过由于是在子线程设置图片时,主线程继续往下走,所以无法准确保证图片加载完成后的设置与onViewAttachedToWindow的先后顺序,我们使用rxjava切换线程,可通过接收CalledFromWrongThreadException后,重新在主线程设置一次图片来做保护。

不过上面的方案由如下问题:由于子线程更新 UI 加上 Try catch 之后,requestLayout 的流程,会将 View 本身及其各层父类的 PFLAG_FORCE_LAYOUT 标志位置为 1 。但是,因为 ViewRootImpl.scheduleTraversals() 未执行,所以,不会触发 View.layout() 重置 PFLAG_FORCE_LAYOUT 标志位,导致,后续再有其他的 UI 操作,因 View 本身及其各层父类的 PFLAG_FORCE_LAYOUT 标志位置还是 1 , 不会触发 ViewRootImpl.requestLayout() 进行 scheduleTraversals() ,而 scheduleTraversals 中会触发 View 的 measure 、layout 、draw 流程进行界面刷新,造成界面展示异常,需要手动调用window.decorView.requestLayout()来进行恢复。但是通过手动调用恢复可能会导致其他不可预测问题,所以方案不推荐。

还有一个办法,就是直接调用updateDrawable(Drawable d)方法去给ImageView将图片预加载进去,下次触发ImageView的requestLayout()和invalidate()时候会直接加载出图片。可惜updateDrawable(Drawable d)被注释为@UnsupportedAppUsage,所以虽然这个方案使用反射的方式测试过可行性,但是还是无法使用。

经过实测,由于应用启动后主线程忙碌,子线程加载图片并设置的操作会在onViewAttachedToWindow之前,所以可以明显提高首页的图片加载速度,不过因为种种问题没有很好的解决方案,此方案暂时无法正式上线。

歪门邪道之解决首屏图片加载闪烁问题相关推荐

  1. H5首屏图片加载优化

    背景 当h5的首屏为一张整图的时候,图片又比较大,加载起来比较慢. 一般常用的方法是将图片无损压缩 常用的压缩网站,缺点 就是压缩后的图 如果在网络较差的情况下,加载也会有一定的延迟,如果网络更加不稳 ...

  2. 微信小程序-首屏视频加载

    项目场景: 微信小程序开发: 实现小程序首页视频预加载功能 1.获取设备的宽和高度 2.小程序video的使用 获取设备的宽和高度 // 获取设备的宽和高度getsize() {let that = ...

  3. 如何解决web端图片加载慢卡顿的问题???

    公司官网上面有一的功能是在后台发布公司动态之后,在前台显示公司动态内容. 但是上上周团建之后,上传的公司动态中的图片加载速度就非常的慢. 图片加载慢的原因有两个: 1.图片过大导致的加载缓慢. 2.网 ...

  4. 【建站指南】解决个人网站图片加载缓慢的问题

    2022年3月25日更新重大警告:Gitee 官方不让做图床了,开启的有防盗链机制.千万不要再使用 Gitee 做图床了,不然图片全部会失效.特别是想搭建个人博客的小伙伴,不要用 Gitee,使用其他 ...

  5. 前端图片加载闪烁问题

    前端页面对于图片等资源来说,加载是需要时间的,即便网页加载速度已经很快了,由于高度被图片撑开的过程,不可避免会出现闪烁,那怎么解决呢?对于图片,默认只设置图片的一个宽或高,那么另一个值就会按照图片真实 ...

  6. vue 首屏优化加载(三)(CND引用)

    # 在根目录 index.html 使用 cnd 节点导入 因为Element依赖Vue,vue.js需要在element-ui之前引入,所以vue.js也要改为cnd的引入方式 <!DOCTY ...

  7. nuxt解决首屏加载慢问题_Vue首屏加载慢

    项目慢慢大起来之后,页面越来越多你会发现第一次进入vue项目变得很慢,这就叫首屏加载慢. 一般有这些常见原因: 有些项目图片很大也没有压缩 一般大图控制在300k以内 小图可以控制到50k以内 可以让 ...

  8. 小程序一次性上传多个本地图片,上拉加载照片以及图片加载延迟解决之道

    一:小程序之一次性上传多个本地相片 最近由于项目需要所以学了下小程序,也做了一些东西,随后便有了以下的一些总结了,现在说说如何使用小程序一次性上传多个本地相片. 问题描述 最近做项目的时候要实现一个上 ...

  9. android 图片加载 软引用_Android 解决图片大量下载:软引用必须懂4点

    1.对象的强.软.弱和虚引用 为了能更加灵活控制对象的生命周期,需要知道对象引用的4中级别,由高到低依次为 :强引用.软引用.弱引用和虚引用 备注: 这四种的区别: ⑴强引用(StrongRefere ...

最新文章

  1. openlayers 可以实现3d地图效果吗_OpenLayers教程:地图标注
  2. Flume的Channel
  3. 使用代码创建具有organization unit的opportunity
  4. 如何在管理员页面查看知识星球活跃度和更多明细
  5. Nature150岁生日:盘点史上十大重磅论文,中国13篇文章登上封面!
  6. 06512oracle数据库,ORA-06512 – 专业Oracle数据库恢复,或许是您恢复数据的最后机会@phone:13429648788 - 专业Oracle数据库恢复技术支持...
  7. python技能(1)-map函数
  8. 【报告分享】抖音-2019年下半年短视频平台营销通案.pdf
  9. Tomcat详解(三)——tomcat多实例
  10. Unreal 凹多边形三角化
  11. word参考文献编号、引用、修改
  12. 语音识别-语音技术-自然语言处理
  13. Matlab Coder杂记
  14. PHY卡 网卡区别联系
  15. 教育云助武汉大学实现校园信息化
  16. 利用Excel饼图画出八等份圆
  17. python调整图片大小reshape_将不同大小的图像调整为28x28图像并将其转换为一个csvfi...
  18. 计及需求侧响应日前、日内两阶段鲁棒备用优化(Matlab代码实现)
  19. 计算机网络局域网的组建实验报告,《计算机网络》局域网的组建与测试实验报告...
  20. 我有一个自己的数字图书馆

热门文章

  1. 小写金额转大写c++
  2. 输入大小写混合的字母,大写转小写,小写转大写
  3. Java程序从编写到运行
  4. Javaweb ajax实现分页
  5. “左手画圆,右手画方”
  6. 优酷视频在网站里播放
  7. 助推建筑业数字化转型升级,紫光云再出招
  8. 【职场攻略】职场社交之三大巧言攻略
  9. 从事java的年龄_请教前辈们:JAVA的职业有年龄限制吗
  10. lzo的正确c语言代码,LZO 使用跟介绍