標籤:列表 dataset https http etc you getc position 分享
關鍵:public final void notifyItemChanged(int position, Object payload)
RecyclerView局部重新整理大家都遇到過,有時候還說會遇見圖片閃爍的問題。
最佳化之前的效果:
最佳化之後的效果:
如果想單獨更新一個item,我們通常會這樣做,代碼如下:
mLRecyclerViewAdapter.notifyItemChanged(position);
這裡的position就是那個清單項目的索引,調用這個方法可以更新一個Item的UI(當然,你要是直接調用notifyDataSetChanged()方法也可以,但這樣會造成其他不需要更新的item也會重新整理)。
即便如此,圖片閃爍還是出現了,什麼原因引起來的呢,這裡猜測可以有如下幾個原因:
流傳甚為廣泛的一種說法,imageView的寬高不固定導致的(wrap_content)?
是RecyclerView內建的更新動畫效果導致的?
是因為圖片載入架構(glide 的 animte)的動畫效果導致的?
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動畫效果)。
Android RecyclerView局部重新整理那個坑