Android RecyclerView局部刷新那個坑

關鍵:public final void notifyItemChanged(int position, Object payload)git

RecyclerView局部刷新你們都遇到過,有時候還說會碰見圖片閃爍的問題。github

優化以前的效果:api

這裏寫圖片描述

優化以後的效果:框架

這裏寫圖片描述

若是想單獨更新一個item,咱們一般會這樣作,代碼以下:ide

mLRecyclerViewAdapter.notifyItemChanged(position);

這裏的position就是那個列表項的索引,調用這個方法能夠更新一個Item的UI(固然,你要是直接調用notifyDataSetChanged()方法也能夠,但這樣會形成其餘不須要更新的item也會刷新)。測試

即使如此,圖片閃爍仍是出現了,什麼緣由引發來的呢,這裏猜想能夠有以下幾個緣由:優化

  1. 流傳甚爲普遍的一種說法,imageView的寬高不固定致使的(wrap_content)?動畫

  2. 是RecyclerView自帶的更新動畫效果致使的?spa

  3. 是由於圖片加載框架(glide 的 animte)的動畫效果致使的?翻譯

  4. getView中(RecyclerView中是onBindViewHolder)加載圖片的時候,設置一個tag,當發現這個imageView的tag和以前的tag一致時就不加載。

這裏咱們再也不對上面的緣由進行具體的分析,針對上面可能引發閃爍的緣由進行一一驗證後的結果是使人感到失望的:都不是引發圖片閃爍的根本緣由。

那麼怎麼解決這個圖片閃爍的問題呢?經過查看api,咱們發現了另外一個方法:

這裏寫圖片描述

重點看payload參數介紹:

payload Optional parameter, use null to identify a "full" update

翻譯過來就是若是payload參數是null,那麼就會來一個「完整的」更新,也就是說會所有更新。

咱們再看一下mLRecyclerViewAdapter.notifyItemChanged(position)的源碼:

這裏寫圖片描述

從源碼中看到,notifyItemChanged(position)調用了 notifyItemRangeChanged(int positionStart, int itemCount)方法,源碼以下:

這裏寫圖片描述

notifyItemRangeChanged(int positionStart, int itemCount)方法最終仍是調用了notifyItemRangeChanged(int positionStart, int itemCount, Object payload)方法,只是payload參數是null。

那麼若是payload傳一個不爲null的參數,就能夠實現對列表項中的具體控件更新了嗎?咱們經過代碼驗證下。

模擬更新一條數據:

這裏寫圖片描述

這裏,咱們將payload參數賦值爲」jdsjlzx」,固然你也能夠賦值爲其餘值,只要不空就行。

重寫adapter中的onBindViewHolder(RecyclerView.ViewHolder holder, int position, List payloads)方法:

這裏寫圖片描述

若是payloads列表不是空的,如上圖所示,你就能夠在else代碼塊裏面刷新你想更新的控件了(記得不須要更新的控件就不要寫在這裏了)。

注意:

以上代碼都是結合LRecyclerView框架來測試的,想要體驗完整demo,請參考:https://github.com/jdsjlzx/LRecyclerView

總結

由此看來,RecyclerView作局部刷新仍是很是容易的,其實就是使用好帶payload參數的這個notifyItemChanged方法,以及重寫帶payload的這個onBindViewHolder方法,在onBindViewHolder中去刷新你想更新的控件便可。

PS:

拿朋友圈來講,我發一張照片,這就是一個item,但這個item裏還要加上贊和評論。 
當我有評論和贊要刷新時,我須要判斷當前要改動的item是不是屏幕中的可見位置。若是是,經過調用帶payload參數的這個notifyItemChanged方法更新item,就能達到只刷贊或者只刷評論,而不用從新加載照片(也就是圖片閃爍的緣由)的效果。

怎麼判斷當前position是位於屏幕中呢?下面給出參考代碼:

private void doAnim(int position) {
        int firstItemPosition = layoutManager.findFirstVisibleItemPosition();
        if (position - firstItemPosition >= 0) {
            //獲得要更新的item的view
            View view = mRecyclerView.getChildAt(position - firstItemPosition + 1);
            if (null != mRecyclerView.getChildViewHolder(view)) {
                ProductsViewHolder viewHolder = (ProductsViewHolder) mRecyclerView.getChildViewHolder(view);

                //do something

            }

        }

    }

上面代碼同時也獲取到了ViewHolder視圖,有了ViewHolder,你還能夠作其餘操做哦(好比item動畫效果)。

相關文章
相關標籤/搜索