有關RecyclerView.Adapter 的 notifyItemChanged(int position, @Nullable Object payload) 方法
今天在看某個專案的原始碼的時候,無意間看到了 RecyclerView.Adapter 的 notifyItemChanged(int position, @Nullable Object payload)
方法,以前沒有見過,後來自己查來之後,才知道這個是與 RV 的 Item 區域性重新整理有關的。
平時一般是用 notifyItemChanged(int position)
方法來進行區域性重新整理,但是這個區域性重新整理是通過回撥 onBindViewHolder(@NonNull VH holder, int position)
該方法重新整理指定的 item 的整個檢視,如果該視圖裡麵包含圖片什麼的,如果邏輯處理不當會導致圖片也被重新重新整理而使檢視在效果閃一下。
而如果使用 notifyItemChanged(int position, @Nullable Object payload)
方法的話,則會回撥 onBindViewHolder(@NonNull VH holder, int position,@NonNull List<Object> payloads)
方法,然後再該方法中就可以使用 payloads
引數來進行佈局的重新整理。
先用一個例項來演示一下:
假設 RV 中的 Item 包括一個 ImageView、兩個 TextView,然後整個 Item 設定了一個點選事件,當 Item 被點選之後,就要為內部對應的兩個 TextView 更新一下文字資訊,如下圖所示:
然後是省略之後的主要程式碼:
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> {
private List<ItemBean> data;
......
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
ItemBean itemBean=data.get(position);
holder.tv1.setText(itemBean.str1);
holder.tv2.setText(itemBean.str2);
holder.iv.setImageResource(R.mipmap.ic_launcher);
}
//要注意,當上下滑動 RV 導致 Item 因複用更新檢視時,也會走該方法的,但是此時 payloads 為空
//所以應該注意在該方法中重新整理的狀態應該儲存到 data 對應的 bean 中,使更新時能夠讀取到正確的狀態而展現出正確的效果
//否則在上下滑動後,原位置的 Item 效果會退回到區域性更新之前
@Override
public void onBindViewHolder(ViewHolder holder, int position, List<Object> payloads) {
if (payloads.isEmpty()) {
//payloads 為 空,說明是更新整個 ViewHolder
onBindViewHolder(holder, position);
} else {
ItemBean itemBean=data.get(position);
//將需要重新整理的狀態儲存到 ItemBean 對應的成員變數中
itemBean.str1 += (String) payloads.get(0);
itemBean.str2 += (String) payloads.get(1);
holder.tv1.setText(itemBean.str1);
holder.tv2.setText(itemBean.str2);
}
}
class ViewHolder extends RecyclerView.ViewHolder {
final TextView tv1,tv2;
final ImageView iv;
public ViewHolder(View itemView) {
super(itemView);
tv1 = itemView.findViewById(R.id.tv1);
tv2 = itemView.findViewById(R.id.tv2);
iv = itemView.findViewById(R.id.iv);
itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
notifyItemChanged(getAdapterPosition()," update for 1");
notifyItemChanged(getAdapterPosition()," update for 2");
}
});
}
}
}
這裡需要注意的是,在 onBindViewHolder(ViewHolder holder, int position, List<Object> payloads)
中佈局重新整理時,同時需要將重新整理的狀態儲存到對應的 bean 中,否則在上下滑動後,原 position 位置的 item 會退回到未區域性重新整理之前的狀態。就像下圖的效果:
@Override
public void onBindViewHolder(ViewHolder holder, int position, List<Object> payloads) {
if (payloads.isEmpty()) {
onBindViewHolder(holder, position);
} else {
ItemBean itemBean=data.get(position);
// itemBean.str1 += (String) payloads.get(0);
// itemBean.str2 += (String) payloads.get(1);
// holder.tv1.setText(itemBean.str1);
// holder.tv2.setText(itemBean.str2);
//直接重新整理該區域性檢視,而不儲存相應的狀態到 bean 中
holder.tv1.setText(itemBean.str1 + payloads.get(0));
holder.tv2.setText(itemBean.str2 + payloads.get(1));
}
}
之後,需要補充幾點:
1、如果重寫了 onBindViewHolder(ViewHolder holder, int position, List<Object> payloads)
方法,那麼不管是 RV 在初始化時,還是在因為上下滑動而重新整理時,都會走該方法(此時 payloads
為空),而不走 onBindViewHolder(ViewHolder holder, int position)
方法,因此,需要完善邏輯,在 payloads
為空時手動呼叫 onBindViewHolder(holder, position);
或者將原本 onBindViewHolder(holder, position);
的邏輯寫到這裡。
2、每一個具體的 position 都會在 onBindViewHolder(holder, position, payloads)
方法對應一個單獨的 payloads
。
這一點測試一下即可知道,假設為 ItemView 的點選事件補充如下程式碼:
itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
notifyItemChanged(getAdapterPosition()," update for 1 ->"+getAdapterPosition());
notifyItemChanged(getAdapterPosition()," update for 2 ->"+getAdapterPosition());
//補充的程式碼
notifyItemChanged(getAdapterPosition()+1," update for 1 ->"+(getAdapterPosition()+1));
notifyItemChanged(getAdapterPosition()+1," update for 2 ->"+(getAdapterPosition()+1));
}
});
則可以看到如下的效果:
position 為 1 和 2 分別重新整理了對應的檢視,且兩者沒有交叉。
3、假設在 notifyItemChanged(position, payload)
方法中傳入的 payload
為 null,則會把 position
對應的 List<Object> payloads
清空,而在呼叫 onBindViewHolder(ViewHolder,int,List)
之前 notifyItemChanged(position, payload)
將不會起作用。
這個可以在原始碼的註釋中瞭解到。
其中標記處的大致意思是:
notifyItemRangeChanged()中 payload == null 時將清除該專案上的所有現有的 payloads,並阻止將來
payloads 增加元素,直到呼叫 onBindViewHolder(ViewHolder,int,List)
然後通過實測也可以驗證:
itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
notifyItemChanged(getAdapterPosition()," update for 1 ->"+getAdapterPosition());
notifyItemChanged(getAdapterPosition()," update for 2 ->"+getAdapterPosition());
notifyItemChanged(getAdapterPosition(),null);
notifyItemChanged(getAdapterPosition()," update for 3 ->"+getAdapterPosition());
notifyItemChanged(getAdapterPosition()," update for 4 ->"+getAdapterPosition());
}
將 ItemView 的點選事件改成上述,然後執行,點選 Item,此時雖然會呼叫 onBindViewHolder(ViewHolder,int,List)
,但是 payloads.size() == 0
。
4、連續多次的呼叫 notifyItemChanged(position, payload)
,但是隻會回撥一次
onBindViewHolder(ViewHolder,int,List)
。具體原因需要分析原始碼,目前暫不深究。
相關推薦
有關RecyclerView.Adapter 的 notifyItemChanged(int position, @Nullable Object payload) 方法
今天在看某個專案的原始碼的時候,無意間看到了 RecyclerView.Adapter 的 notifyItemChanged(int position, @Nullable Object payload) 方法,以前沒有見過,後來自己查來之後,才知道這個是與
getView(int position, View convertView, ViewGroup parent)
向上滑動 ListView ,item1 檢視被滑出螢幕, item1檢視被 回收到 Recycler( View 緩衝池) 中,如要顯示 item8檢視,先從快取池中取出item1檢視,更新 item8 需要顯示的資料,變成了item8檢視,把它放到ViewGroup中,ListView要
裝飾模式應用 為RecyclerView.Adapter新增上拉載入更多
這個包裝類主要有兩個關鍵點: 第一個是列表尾部新增一個條目,用於顯示各種載入的狀態,就是添加了一個特殊型別的holder。 第二個是監控列表滾動,滾動到我們新增的那個holder的時候,觸發我們需要的操作,比如修改holder裡的狀態文字等。 注意問題: 以前做過兩一個實
基於 Multitype 開源庫封裝更好用的RecyclerView.Adapter
前言 MultiType 這個專案,至今 v3.x 穩定多時,考慮得非常多,但也做得非常剋制。原則一直是 直觀、靈活、可靠、簡單純粹(其中直觀和靈活是非常看重的)。 這是 MultiType 框架作者給出的專案簡述。 作為一個 RecyclerView 的 Adapter 框架,感覺這專案的設
RecyclerView.Adapter介面卡通用化改造
RecyclerView 是谷歌給開發者的福利,比以往的ListView更加強大,效能更大,具體原始碼分析,我們下次講。本篇主要介紹如何在專案中提煉程式碼,增強它的適配性。下面就介紹我的思路。 首先一般編碼有如下幾個問題。 1.列表資料,需要寫一個RecyclerView.Adapter
繼承RecyclerView.Adapter使用泛型遇到的問題
轉自:http://my.oschina.net/buobao/blog/651007 在使用RecyclerView的時候遇到了一個很坑的問題,記錄這個大坑! 首先,在使用RecyclerView.Adapter的時候定義了一個BaseListAdapter,程式碼如下:
封裝RecyclerView Adapter 實現可新增多個header和footer,可設定loadingView,低耦合的多種佈局。
多種佈局的recyclerview的普通寫法是重寫RecyclerView.Adapter的getItemViewType返回不同position上的type,在onCreateViewHolder(ViewGroup parent,int viewType
Android RecyclerView Adapter及Holder的封裝【原創】
專案中使用到了橫向的ListView樣子的功能,一開始使用Gallery做,由於Gallery的自帶彈性功能,效果不理想,於是使用網上的一些開源的橫向ListView,但是效果很卡, 最後使用了v7包中的RecyclerView,初次使用,不太熟練,對其進行了簡單的封裝
ButterKnife結合RecyclerView.Adapter一起使用
直接上程式碼: @Override public MainHodler onCreateViewHolder(ViewGroup parent, int viewType) { View view = LayoutInflater.from(pare
RecyclerView.Adapter優化了嗎?
昨天寫了一篇「還在用ListView?」講的內容是RecyclerView的使用技巧以及一些常用的開源庫,有朋友反饋“我已經在用recyclerview了”,那麼如何讓它更好用呢?此時我想到了優化RecyclerView.Adapter,因為在Recycl
RecyclerView Adapter 優雅封裝,一個Adapter搞定所有列表
專案中,我們用得最多的元素就是列表了,在Android 中,實現列表用原生的RecyclerView就能滿足需求,關於RecyclerView 的基礎使用這裡不做過多的介紹,網上有太多的博文介紹了。本篇文章將介紹自己封裝的一個Adapter,幫你快速高效的新增一個列表(包
封裝RecycleView的 RecyclerView.Adapter的方式
目錄 一、BaseQuickAdapter的寫法 public abstract class BaseQuickAdapter<T> extends RecyclerView.Adapter<BaseViewHolder>
RecyclerView 滾動到指定position,並置頂
今天寫頁面有一個需求是這樣的: 有一個廣告條,顯示2條廣告資訊並且,可以自動向上滾動。what? 2條看得我懵逼,一般我們看到的廣告條都是一條一條切換,使用ViewFlipper就能夠實現,但ViewFlipper不能顯示2條。苦思冥想下,覺得使用Recycl
Writing a RecyclerView Adapter in Kotlin (KAD 16)
An interesting way to see how Kotlin simplifies your life is by creating a RecyclerView Adapter. You’ll see that the code can be organized in such a
ButterKnife在RecyclerView adapter中的使用
ButterKnife是一個用起來十分方便的開源庫,我們只需要用一個小小的外掛ButterKnifeZenezny就免去了寫一大袋findViewbyId的書寫,不過在adapter中,外掛自動生成的方
RecyclerView.Adapter notifyDataSetChanged 不起作用
最近專案裡要添加個聊天功能,我們使用的是環信SDK。 如果應用啟動,不在聊天介面,接收到訊息後就彈出通知欄訊息通知使用者,點選進入聊天介面。 如果使用者已經在聊天介面,就要將接收到的資料新增到adapter裡,動態顯示訊息。 問題卡在,接收到訊息後呼叫更新
RecyclerView.Adapter結合ButterKnife封裝
public class BaseViewHolder extends RecyclerView.ViewHolder { View mView ; public BaseViewHo
RecyclerView Adapter簡單封裝
前言 今天是新年第一天,本來打算在上一年的最後一天寫下來的,但是由於玩的時間長了一點,所以今天才寫,算是在新的一年開一個好頭,新年新氣象嘛! 至於為什麼要寫這個文章吶!由於專案中以前都是用ListView實現的列表,很多東西都已經
Android 對封裝RecyclerView.Adapter講解
首先先得知RecyclerView.Adapter有什麼方法,這樣才知道與ListView的BaseAdapter有什麼區別: public class MyAdapter extends RecyclerView.Adapter { @Over
RecyclerView.Adapter 點選事件
package gaga.erlan.apps.aiyesoft.com.gaga; import android.content.Intent; import android.content.SharedPreferences; import android.os.Bu