安卓易學,爬坑不易—騰訊大佬的RecyclerView局部刷新爬坑之路

前言

安卓開發者都知道,RecyclerView比ListView要靈活的多,但不能否認的裏面的坑也一樣埋了很多人。下面讓咱們看看騰訊開發工程師用實例講解本身踩坑時的解決方案和心路歷程。html

話說有圖有真相,首先來對比一下局部刷新先後的效果:面試

優化以前的效果:api

優化以後的效果:框架

能夠看到,優化以後,列表中的這張大圖不在有一閃一閃亮晶晶的效果了! ide

那麼,這是如何作到的呢?這是本文的重點,本文的大綱主要包括:學習

  1. 分析爲何會閃一下
  2. 對分析的可能形成閃動的問題進行解決
  3. 驗證是否解決

 1、爲何會閃一下?

咱們的需求是你們已經看到了,點擊打分,彈出一個對話框,點擊一個分數,這時候,經過一些列複雜的轉換(固然不是本文的論述的重點),這時候到了要更新列表項了,如是很天然,咱們會這麼作:優化

由於,操做的那個列表項你是知道他的position,因此你能夠這麼作,(固然,我以前是直接notifyDataSetChanged的,這個會照成因此不不要的item也會刷新)然而,閃動仍是出現了,那麼我開始懷疑:動畫

  1. 流傳甚爲普遍的一種說法,imageView的寬高不固定致使的(wrap_content)?
  2. 這個是RecyclerView自帶的更新動畫效果致使的?
  3. 這個是由於圖片加載框架(glide 的 animte)的動畫效果致使的?
  4. getView中(RecyclerView中是onBindViewHolder)加載圖片的時候,設置一個tag,當發現這個imageView的tag和以前的tag一致時就不加載

 2、帶着思考,就去嘗試吧!

一、對於第一種,個人作法是本身寫了一個自定義的imageView,重寫omMeasure方法,以下: spa

由於咱們的這個列表項中的圖片是(高=寬)的,所以,我才這麼寫,這樣寫也有一個好處,不用在onBindViewHolder中去動態的計算出高度,而後在已layoutParm的方式設置給imageView,相信很多小夥伴都作過了吧! 3d

然而,遺憾的是,他並無解決閃一下的問題!此時這個閃動的緣由顯然不在這裏,可是這裏作的,能夠保留下來。

二、對於第二種說法,我參考了這裏http://stackoverflow.com/ques...

的作法:

以及也嘗試了這種

然而,那種漸變的閃動消失了,可是,取而代之的是一種更加不可接受的閃動,這裏就不用gif展現了,所以緣由也並不在此處。

三、對於對三種說法,我也去嘗試了一下將glide加載改成:

然而獲得的依然是一個失望的結果,依然沒有解決閃動的問題,緣由也不在此處。

4、那麼,就剩下最後一個猜想了,那麼會不會是它呢?那就試試吧,因而代碼改成:

這裏的作法其實就是設置Tag,那麼是騾子是馬,拉出來溜溜吧,結果更加使人髮指,如圖:

好吧,此時已經有點崩潰了,顯然這個也不是我要的結果,那麼此時是否應該在靜下來想想,本身對於可能的幾種緣由作過的一些對策,是否有哪裏遺漏了。通過思考,發現並無!!那麼必定是還有其餘的緣由,沒有考慮到!

仍是去翻一翻RecyclerView的api吧,我注意到了這個api:

能夠看到這裏有一個payload的參數,use null to identify a "full" update這是說若是傳null就是所有更新,回過頭去看一看咱們以前的調用方式:

看一下源碼,發現

實際上,payload這個參數就是傳的null,那也就是說若是傳一個不爲null的參數,就能夠對列表項中的具體控件更新了?

http://stackoverflow.com/ques...

我瞭解到這個方法的使用方式是這樣的:

然來,onBindViewHolder有這麼一個重載方式,如是我也這麼作了,在下面這個重載中,去更新我想更新的控件:

而後,更新的方式變成了這種:

是騾子是馬,那就在遛一遛吧!

然而,依然是會閃一下!!!這這麼會!!!仍是調試一下吧,新重載onBindViewHolder方法有沒有被執行,一更代碼,發現果真沒有被執行!那麼,到底是什麼鬼?去網上查了一下,有人給出了一個解決辦法:

http://stackoverflow.com/ques...

須要重寫這個動畫,讓永遠返回true,已達到newHolder和olderHolder是同一個,然而,這真的就是個人救命稻草嗎?

那麼,是騾子是馬,拉出來溜溜吧,然而,並非馬!!進源碼看一看

發現其實只要咱們傳入的payload不爲空,那麼返回的就是true?重寫有意義嗎?顯然,我重載的onBindViewHolder方法並無執行的緣由顯然不是這個。

那麼,到底,到底問題出在何處?會不會是XrecyclerView的問題?根據調用棧,我看到第一個onBindViewHolder被執行了,往上面跟,發現XrecyclerView的實現果真存在問題!

image

如圖,做者僅僅只實現了,不帶payload的方法,最後adapter調用的只有不帶paylaod的方法!因此,重寫一個吧!

最後!終於達到了想要的效果了,通過此次爬坑,選擇一個開源的框架真滴是須要慎重再慎重。

總結

實際上RecyclerView作局部刷新是很是容易的,其實就是使用好帶payload參數的這個notifyItemRangeChanged方法,以及override帶payload的這個onBindViewHolder方法,在onBindViewHolder中去刷新你想更新的控件便可,並不是是網上傳聞的那些緣由,固然此處爬坑時間之長,也可能更選用開源控件不當有關,因此,選擇開源控件,要謹慎再謹慎!

原文連接:http://wetest.qq.com/lab/view...

閱讀更多

kotlin學習筆記-異常好玩的list集合總結
一份完整的Android Studio搭建Flutter教程

NDK項目實戰—高仿360手機助手之卸載監聽

(Android)面試題級答案(精選版)

相信本身,沒有作不到的,只有想不到的

在這裏得到的不只僅是技術!

image

相關文章
相關標籤/搜索