V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
merpyzf
V2EX  ›  Android

文件下载列表中关于 RecyclerView 中 item 频繁需要更新的问题

  •  
  •   merpyzf · 2018-10-21 12:24:06 +08:00 via Android · 6950 次点击
    这是一个创建于 1985 天前的主题,其中的信息可能已经有所发展或是发生改变。

    目前正在做一个文件下载的功能,现在在 RecyclerView 条目中的 Progressbar 刷新问题上卡住了。项目中是通过观察者模式来监听文件下载的状态,通过回调观察者对象中的 updateProgress(FileInfo fileinfo)方法(回调频率为 50ms)来实现 RecyclerView 中 item 的状态更新。

    目前做了一下几种尝试:

    1. 每次回调 updateProgress(FileInfo fileinfo)通过获取 FileInfo 对象所在 RecyclerView 的 position 位置,对单个 item 进行刷新。虽然可以实现功能,但是由于刷新频率太高,会造成界面卡顿。

    2. 每次回调 updateProgress(FileInfo fileinfo)时 通过调用 notifyDataChanged()方法来对整个 RecyclerView 进行刷新。同样由于更新频率太高滑动起来会感受到明显的卡顿。

    3. 在 ViewHolder 中注册观察者,然后直接在 ViewHolder 中对 item 中的 View 进行刷新。滑动起来的体验最好,但是由于我太菜,对 RecyclerView 的复用机制了解的不深入。目前还想不到合适的逻辑来解决复用导致的显示错乱的问题。

    希望各位大佬给小弟提点建议。

    第 1 条附言  ·  2018-10-22 22:45:13 +08:00
    ==========================>

    依次使用了两种方法来完成了 item 内的进度刷新
    1. 通过过在 ViewHolder 中注册观察者,通过回调直接通过已经获取的 Progressbar 的引用来更新进度
    2. 通过调用 notifyItemChanged()方法来完成进度的更新,由于 RecyclerView 对于单条数据的刷新存在一个默认的动画效果,在刷新的时候回出现闪烁,因此需要通过额外的设置来关闭动画。

    总结:
    第一种方式实现可以在刷新频率很高的情况下都不会出现滑动时界面的卡顿,但是需要考虑 RecyclerView 的复用所造成的数据显示的混乱。
    第二种方式实现起来很简单,但是会有一个问题 50ms 的刷新率会出现明显的卡顿。将刷新频率调整到 100ms 以上之后就感觉不到任何的卡顿。

    综上考虑 50ms 的刷新频率对于进度的更新意义不大,因此目前已将 Progressbar 的刷新频率调整到了 200ms,然后采用第二种的方式进行刷新。

    最后感谢大家给我提出的建议!很感谢大家!
    10 条回复    2018-10-22 22:49:15 +08:00
    maninfog
        1
    maninfog  
       2018-10-21 12:50:03 +08:00 via iPhone   ❤️ 1
    1.增大刷新时间… 50ms 也就是 20 个刷新才 1s ??你设置成 200ms 肉眼根本感受不出来差别好么
    2.搜索 recyclerview payload 可以实现局部中的局部刷新
    HarryQu
        2
    HarryQu  
       2018-10-21 13:02:34 +08:00
    刷新时间设置成 500ms 或者 1s ,体验上都不会太差的。
    HarryQu
        3
    HarryQu  
       2018-10-21 13:12:14 +08:00
    1. 我之前做这种功能, 项目中做了专门的下载模块 ,下载任务直接丢给下载模块。页面刷新通过 EventBus 来解耦。
    例如 EventBus 将需要更新任务的 url 、进度之类的传递过来 , RecyclerView 根据 url 之类的拿到 item 位置 , 然后刷新指定位置的数据。
    2. 你要注意下载刷新间隔问题 , 单个任务 50ms , 如果同时下载多个任务 , 你这个页面会非常卡顿的。因此下载进度刷新间隔为 500 ms 或者 1s。
    GoodRainChen
        5
    GoodRainChen  
       2018-10-22 10:13:29 +08:00   ❤️ 1
    "然后直接在 ViewHolder 中对 item 中的 View 进行刷新"
    不说别的,这个方案就可行啊
    每次 bindView 的时候把 position 更新在 ViewHolder 里,根据 position 选择性监听回调就可以了
    xiaohei233
        6
    xiaohei233  
       2018-10-22 11:06:07 +08:00
    RecyclerView 频繁刷新的时候再快速滑动,会崩溃。我之前遇到是这样的问题,还是控制刷新频率吧。
    BryanYue
        7
    BryanYue  
       2018-10-22 13:53:25 +08:00
    第三点 可以用 Map 缓存对应进度数据,key 就是 position 或者 List 的 position
    不要频繁刷新,可以比较 进度跟之前进度有 1%(可自己定义)差别是 在刷新 UI
    刷新方案推荐第一种 局部刷新方案
    DiffUtil 可以了解下 ,直接比较旧数据 自动刷新 UI,系统封装好了
    merpyzf
        8
    merpyzf  
    OP
       2018-10-22 22:46:39 +08:00
    @maninfog 谢谢,问题已经解决,50ms 的刷新频率确实没什么意义,唯一的意义就是能够带来一丝丝感官上的快感。已修改成 200ms 刷新一次。
    merpyzf
        9
    merpyzf  
    OP
       2018-10-22 22:47:15 +08:00
    @HarryQu 谢谢你,问题已经解决
    merpyzf
        10
    merpyzf  
    OP
       2018-10-22 22:49:15 +08:00
    @GoodRainChen 谢谢,之前就是采用这种方式来刷新的,由于逻辑没控制好导致数据错乱。昨天用了些时间把逻辑理清并解决了数据错乱的问题,使用这种方式真的可以很好的解决这种刷新频率过高的需求,并且滑动的过程中根本不会出现任何卡顿。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   4572 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 37ms · UTC 10:05 · PVG 18:05 · LAX 03:05 · JFK 06:05
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.