細談RecyclerView:(二)重新整理閃爍?不存在的,帶你瞭解RecyclerView區域性重新整理
在第一篇文章中提到到,如果想使用RecyclerView,那麼肯定是需要要建立想對應的Adapter。
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { return null; } public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { } public int getItemCount() { return 0; }
每個方法的作用是什麼,想必就需要我多提了。今天我們要談論的話題是:區域性重新整理。
需求場景
通過比較兩張圖片我們可以發現,這個是要涉及到對單本書的重新整理的。預設狀態下是不會顯示選中的那個圖示的,當點選右上角編輯的按鈕後,所有的書籍都會顯示一個可以選擇的圖示。
現在我們來分析這個需求。比較兩次不同的狀態下書籍的佈局,我們不難發現:輸的封面是一直不變的。更準確的說除了在編輯狀態下多顯示了一個選擇圖示外其他的東西都沒有發生變化。
通過上面的分析,我們可能會想到:能不能在重新整理單個佈局(我習慣稱為Item)的時候只對選擇圖示的顯示和隱藏做更新?看完今天的這篇文章後,你就知道是可以的。
講解
首先我們需要注意一個方法:
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { }
這是我們在覆寫Adapter方法中需要覆寫的一個方法。
在RecyclerView.Adapter的方法中,官方的註釋是這樣的。
/** * Called by RecyclerView to display the data at the specified position. This method should update the contents of the itemView to reflect the item at the given position. * Note that unlike ListView, RecyclerView will not call this method * again if the position of the item changes in the data set unless the item itself is * invalidated or the new position cannot be determined. For this reason, you should only * use the <code>position</code> parameter while acquiring the related data item inside * this method and should not keep a copy of it. If you need the position of an item later * on (e.g. in a click listener), use {@link ViewHolder#getAdapterPosition()} which will * have the updated adapter position. * * Override {@link #onBindViewHolder(ViewHolder, int, List)} instead if Adapter can * handle efficient partial bind. * * @param holder The ViewHolder which should be updated to represent the contents of the * item at the given position in the data set. * @param position The position of the item within the adapter's data set. */ public abstract void onBindViewHolder(VH holder, int position);
大概的意思是:這個方法被呼叫的目的是為了顯示指定位置上的資料。這個方法會通過給定的位置進行重新整理Item的內容。
其實在RecyclerView.Adapter中還存在著另外一個過載的方法。
public void onBindViewHolder(VH holder, int position, List<Object> payloads) { onBindViewHolder(holder, position); }
與含有兩個引數的方法相比,這個方法中多了一個引數:List<Object> payloads。
根據英文的翻譯來講,payloads的意思是“有效載荷”的意思。那麼“有效載荷”又是啥意思呢?
有效載荷是指航天器上裝載的為直接實現航天器在軌執行要完成的特定任務的儀器、裝置、人員、試驗生物及試件等。航天器有效載荷是航天器在軌發揮最終航天使命的最重要的一個分系統。
好吧,其實我也沒懂。那麼我們在搜一下“載荷”是啥意思。
荷載指的是使結構或構件產生內力和變形的外力及其它因素。
這個好像明白點了。
好吧,那我們再看看官方是如何解釋的。
The payloads parameter is a merge list from { #notifyItemChanged(int, Object)} or * { #notifyItemRangeChanged(int, int, Object)}. If the payloads list is not empty, * the ViewHolder is currently bound to old data and Adapter may run an efficient partial * update using the payload info. If the payload is empty, Adapter must run a full bind. * Adapter should not assume that the payload passed in notify methods will be received by * onBindViewHolder(). For example when the view is not attached to the screen, the * payload in notifyItemChange() will be simply dropped.
首先payLoads是一個List<Object>的集合,它來源於兩個方法中的引數:一個是notifyItemChanged(int, Object),另外一個是notifyItemRangeChanged(int, int, Object)。如果payloads不為空,那麼ViewHolder只會更新payloads中傳過來的資訊,也就是進行區域性的更新(run an efficient partial update),如果為空,那麼Adapter需要進行一個全新的繫結。
通過以上的解釋,我們大概明白了:對ViewHolder(Item)進行區域性重新整理的關鍵其實是payloads引數,而如果想實現區域性重新整理,那麼payloads肯定不能為空,而且還需要呼叫notifyItemChanged(int, Object)或者是notifyItemRangeChanged(int, int, Object)的方法以實現區域性重新整理。
那麼現在我們利用payloads來實現需求場景中的功能。
public void onBindViewHolder(BookshelfViewHolder holder, int position, List<Object> payloads) { //當payloads為空時,不需要重新整理的控制元件 if (payloads.isEmpty()) { BookShelfBook book = mBookShelfDataList.get(position); ImageLoader.loadBookCover(holder.bookCoverIv,book.imageUrl); holder.nameTv.setText(book.name); if(book.isRead == Flag.FALSE){ holder.unReadTv.setVisibility(View.VISIBLE); holder.updateTv.setVisibility(View.GONE); }else { if (book.updateCnt > 0) { holder.updateTv.setVisibility(View.VISIBLE); holder.unReadTv.setVisibility(View.GONE); String updateCount = mContext.getText(R.string.update_chapter_count).toString(); holder.updateTv.setText(String.format(updateCount,book.updateCnt)); }else { holder.updateTv.setVisibility(View.GONE); holder.unReadTv.setVisibility(View.VISIBLE); } } holder.layout.setOnClickListener(new NoDoubleClickListener() { protected void onNoDoubleClick(View view) { if (isEdit) { if (book.isSelected) { book.isSelected = false; holder.chooseIv.setSelected(false); mSelectedList.remove(book); if (mSelectedList.size() <= 0) { ((BookShelfFragment)mFragment).showBottomBar(false); } }else { book.isSelected = true; holder.chooseIv.setSelected(true); mSelectedList.add(book); if (mSelectedList.size() > 0) { ((BookShelfFragment)mFragment).showBottomBar(true); } } ((BookShelfFragment)mFragment).setBottomState(mSelectedList.size()); }else { BookDetailActivity.actionStart(mContext,book.bookUuid); } } }); }else { //由於專案中只需要控制選擇框的顯示和隱藏所以只要判斷payloads不為空就行,當然如果你需要實現很多個不同的控制元件重新整理的時候那你還需要進一步判斷payloads以做到更精準的區域性重新整理 if (isEdit) { holder.chooseIv.setVisibility(View.VISIBLE); }else { holder.chooseIv.setVisibility(View.GONE); } if (isAll) { holder.chooseIv.setSelected(true); mSelectedList.clear(); mSelectedList.addAll(mBookShelfDataList); }else { holder.chooseIv.setSelected(false); mSelectedList.clear(); } } }
解釋都寫在程式碼上了,我就不展開講了。總之我們的思路是:當需要控制某個ViewHolder控制元件更新的時候就再更新的時候傳入一個payloads。由於payloads是一個List<Object>所以你可以控制多個控制元件的重新整理。有一點需要注意的是你在呼叫Adapter的更新方法的時候一定要呼叫含有List<Object>的方法,要麼是不會奏效的。這個在官方的方法註釋中也提到了。
為啥要寫這篇文章
如果使用兩次引數的方法沒有問題的話,我想我也不會去用含三個引數的方法,主要是在開發的過程中遇到了一個重新整理閃爍的問題。大概的意思就是當我點選某個Item的時候,另外一個Item的圖書封面會消失,再點選然後又會顯示。所以就想著能不能做到區域性重新整理,畢竟圖書的封面在預設狀態下和編輯的狀態下是不會發生改變的。所以就Google了一下,發現是可以的。所以在實現專案功能的時候也希望自己能夠在以後的開發中能夠多使用區域性重新整理以減少不必要的更新。
最後
非常感謝您的閱讀,如果文章中有錯誤或值得商榷的地方還希望您能夠在評論區指出。
相關文章
- RecyclerView 區域性重新整理的坑View
- Android RecyclerView 區域性重新整理原理AndroidView
- RecyclerView重新整理View
- RecyclerView重新整理機制View
- Android實現帶動畫的下拉重新整理RecyclerViewAndroid動畫View
- 安卓易學,爬坑不易—騰訊老司機的RecyclerView區域性重新整理爬坑之路安卓View
- 優雅地重新整理RecyclerViewView
- 實現RecyclerView下拉重新整理View
- RecyclerView使用,優化,條目閃爍問題View優化
- 自己動手寫RecyclerView的下拉重新整理View
- win10工作列閃爍重新整理怎麼辦 win10工作列閃爍重新整理的方法Win10
- Android recyclerview刪除item重新整理列表AndroidView
- jQuery重新整理區域性divjQuery
- RecyclerView使用之——資料重新整理混亂及解決方案View
- RecyclerView下拉重新整理 上拉載入 原理DemoView
- RecyclerView超簡單demo(區域性更新取代ListView)View
- HTML頁面區域性重新整理HTML
- RecyclerView與下拉重新整理控制元件滑動衝突的解決View控制元件
- android Listview,gridview區域性重新整理,部分重新整理AndroidView
- Android 列表(ListView、RecyclerView)不斷重新整理最佳實踐AndroidView
- 給RecyclerView擴充套件下拉重新整理上拉載入View套件
- 記錄recyclerview的閃退問題解決View
- 微信小程式setData區域性重新整理列表微信小程式
- RecyclerView.smoothScrollToPosition瞭解一下View
- 真正帶你搞懂RecyclerView的快取機制View快取
- 你必須瞭解的RecyclerView的五大開源專案-解決上拉載入、下拉重新整理和新增Header、Footer等問題ViewHeader
- win10桌面重新整理圖示不停閃怎麼處理 win10桌面圖示不停重新整理閃爍解決方法Win10
- 關於Paging + Room,RecyclerView重新整理時的空指標異常OOMView指標
- 使用ajax實現頁面區域性重新整理
- vue中重新整理頁面時去閃爍,提升體驗方法Vue
- recyclerView的側拉效果。上拉載入。下拉重新整理,點選事件等等View事件
- 微信小程式點贊、評論區域性重新整理微信小程式
- 使用jQuery的load方法實現div區域性重新整理jQuery
- vue -- v-cloak解決重新整理或者載入出現閃爍(顯示變數)Vue變數
- Ajax區域性頁面重新整理和History API結合的陷阱API
- 短視訊平臺原始碼,單條目重新整理notifyItem 去除閃爍動畫原始碼動畫
- RecyclerViewView
- 介面無小事(一): RecyclerView+CardView瞭解一下View