日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

RecyclerView的优化:RecycledViewPool

發布時間:2025/4/16 编程问答 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 RecyclerView的优化:RecycledViewPool 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

原文出處:https://yrom.net/blog/2015/05/30/recyclerView-tips-1-recycledviewpool/

想必Tabs+ViewPager+ListView 結合使用的場景在你的Android手機中的各大應用里并不少見,比如最為典型的網易新聞。

眾所周知,用RecyclerView可以非常簡單的替代掉ListView。可僅僅就為了將ListView換成RecyclerView,這換湯不換藥的做法顯然不足以讓人心動。

如果我說,再用上RecycledViewPool,可以使你的布局渲染速度、ViewPager滑動流暢度上升一個檔次,你會心動并行動嗎?

RecycledViewPool是什么?

關于RecycledViewPool,官方文檔是這樣說的:

Recycled view pools allow multiple RecyclerViews to share a common pool of scrap views. This can be useful if you have multiple RecyclerViews with adapters that use the same view types, for example if you have several data sets with the same kinds of item views displayed by a ViewPager. RecyclerView automatically creates a pool for itself if you don’t provide one.

簡言之就是,你可以給RecyclerView設置一個ViewHolder的對象池,這個池稱為RecycledViewPool,這個對象池可以節省你創建ViewHolder的開銷,更能避免GC。即便你不給它設置,它也會自己創建一個。

如此說來,如果多個RecylerView間共用一個RecycledViewPool是不是能讓你的UI更加的“順滑”?

使用RecycledViewPool

RecycledViewPool使用起來也是非常的簡單:先從某個RecyclerView對象中獲得它創建的RecycledViewPool對象,或者是自己實現一個RecycledViewPool對象,然后設置個接下來創建的每一個RecyclerView即可。

需要注意的是,如果你使用的LayoutManager是LinearLayoutManager或其子類(如GridLayoutManager),需要手動開啟這個特性:

layout.setRecycleChildrenOnDetach(true) RecyclerView view1 = new RecyclerView(context); LinearLayoutManager layout = new LinearLayoutManager(context); layout.setRecycleChildrenOnDetach(true); view1.setLayoutManager(layout); RecycledViewPool pool = view1.getRecycledViewPool(); //... RecyclerView view2 = new RecyclerView(context); //... (set layout manager) view2.setRecycledViewPool(pool); //... RecyclerView view3 = new RecyclerView(context); //...(set layout manager) view3.setRecycledViewPool(pool);

ViewPager中使用原理同上,只是你得通過ViewPagerAdapter傳遞個下一個RecyclerView。

代碼示例如下:

public class PagerActivity extends AppCompatActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_pager);ViewPager pager = (ViewPager) findViewById(R.id.pager);pager.setAdapter(new PageAdapter(getSupportFragmentManager()));}static class PageAdapter extends FragmentPagerAdapter{RecyclerView.RecycledViewPool mPool = new RecyclerView.RecycledViewPool();public PageAdapter(FragmentManager fm) {super(fm);}@Overridepublic Fragment getItem(int i) {RecyclerViewFragment f = new RecyclerViewFragment();f.mPool = mPool;return f;}// ...}public static class RecyclerViewFragment extends Fragment{RecyclerView.RecycledViewPool mPool;@Nullable@Overridepublic View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {RecyclerView view = new RecyclerView(inflater.getContext());LinearLayoutManager layout = new LinearLayoutManager(inflater.getContext());layout.setRecycleChildrenOnDetach(true);view.setLayoutManager(layout);if (mPool != null) {view.setRecycledViewPool(mPool);}view.setAdapter(...);return view;}// ...} }

布局xml:activity_pager.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"><android.support.v4.view.ViewPager android:id="@+id/pager"android:layout_width="match_parent"android:layout_height="match_parent"><android.support.v4.view.PagerTitleStrip android:id="@+id/tabs"android:layout_width="match_parent"android:layout_height="wrap_content"/></android.support.v4.view.ViewPager> </LinearLayout>

詳見 https://gist.github.com/yrom/728237025575005a8fd3

More Tips

RecycledViewPool是依據ItemViewType來索引ViewHolder的,所以你必須確保共享的RecyclerView的Adapter是同一個,或view type 是不會沖突的。

RecycledViewPool可以自主控制需要緩存的ViewHolder數量:
mPool.setMaxRecycledViews(itemViewType, number); 畢竟池子里的水并不是越深越好。

RecyclerView可以設置自己所需要的ViewHolder數量,只有超過這個數量的detached ViewHolder才會丟進ViewPool中與別的RecyclerView共享。

recyclerView.setItemViewCacheSize(10);

在合適的時機,RecycledViewPool會自我清除掉所持有的ViewHolder對象引用,不用擔心池子會“側漏”。當然你也可以在你認為合適的時機手動調用clear()

用RecyclerView快速實現列表頁面

如一個簡單的列表場景:TodoList。

分頁加載現有Todo
現有數據基礎上增、刪、改
RecyclerView的使用在此就不贅述了,本文主要討論RecyclerView.Adapter的實現

使用最簡單的ArrayList實現,如下:

class ListAdapter extends RecyclerView.Adapter<TodoViewHolder> {final ArrayList<Item> mData;final LayoutInflater mLayoutInflater;public SortedListAdapter(Context context) {mLayoutInflater = LayoutInflater.from(context);mData = new ArrayList<>();}public void addItem(Item item) {mData.add(item); // 需要自己通知更新}@Overridepublic TodoViewHolder onCreateViewHolder(final ViewGroup parent, int viewType) {return new TodoViewHolder (mLayoutInflater.inflate(R.layout.list_todo_item, parent, false));}@Overridepublic void onBindViewHolder(TodoViewHolder holder, int position) {holder.bindTo(mData.get(position));}@Overridepublic int getItemCount() {return mData.size();} }

這樣的Adapter一個顯而易見的問題就是,如何做數據的去重。

添加一項數據:最簡單的是在addItem()之前,遍歷一次mData,定位后再決定是插入還是更新現有數據,并調用notifyItemInserted(pos)。
添加多個數據:多次重復上面的方法…
對于少量數據來說這樣做并不見得有什么問題,而且寫得多了,都有自己封裝好的諸如ArrayObjectAdapter之類方便使用。

這樣就夠了嗎?

答案肯定是不。Android Support Library 悄悄給我們提供了一個叫SortedList的工具類,它默默的藏在support庫的角落中,鮮為人知。

SortedList?

文檔對它的定義:

  • 是一個有序列表
  • 數據變動會觸發回調SortedList.Callback的方法,如onChanged()
  • 構造一個SortedList需要實現它的回調SortedList.Callback,并由其來定義數據的排序和數據的唯一性。它有一個實現類SortedListAdapterCallback就是RecyclerView.Adapter與SortedList交互的秘密武器。

    示例

    改造后的ListAdapter:

    class SortedListAdapter extends RecyclerView.Adapter<TodoViewHolder> {final SortedList<Item> mData;final LayoutInflater mLayoutInflater;public SortedListAdapter(Context context) {mLayoutInflater = LayoutInflater.from(context);mData = new SortedList<Item>(Item.class, new SortedListAdapterCallback<Item>(this){@Overridepublic int compare(Item t0, Item t1) {// 實現這個方法來定義Item的顯示順序int txtComp = t0.mText.compareTo(t1.mText);if (txtComp != 0) {return txtComp;}if (t0.id < t1.id) {return -1;} else if (t0.id > t1.id) {return 1;}return 0;}@Overridepublic boolean areContentsTheSame(Item oldItem,Item newItem) {// 比較兩個Item的內容是否一致,如不一致則會調用adapter的notifyItemChanged()return oldItem.mText.equals(newItem.mText);}@Overridepublic boolean areItemsTheSame(Item item1, Item item2) {// 兩個Item是不是同一個東西,// 它們的內容或許不一樣,但id相同代表就是同一個return item1.id == item2.id;}});}public void addItem(Item item) {mData.add(item);// 會通過SortedListAdapterCallback自動通知更新}...@Overridepublic int getItemCount() {return mData.size();} }

    雖然相對ListAdapter代碼量變多了,但是調用者卻再也不用關心數據的去重與通知更新的問題。這一切都有SortedListAdapterCallback幫你自動處理好了。

    單單只這一個好處其實并不值得勞師動眾去改掉現有Adapter使用SortedList,但它另外還有一個令人稱贊并喜愛的功能:批量更新(Batched Updates)。

    就如實現添加多個數據:

    void addItems(List<Item> items){mData.beginBatchedUpdates(); // 開始批量更新mData.addAll(items); // 更新一批數據mData.endBatchedUpdates(); // 結束更新 }

    批量刪除:

    void deleteItems(List<Item> items){mData.beginBatchedUpdates(); // 開始批量更新for(Item item : items){ // 刪除一批數據mData.remove(item);}mData.endBatchedUpdates(); // 結束更新 }

    等等。
    如例子所示,調用beginBatchedUpdates()之后,所有的對SortedList操作都會等到endBatchedUpdates()之后一起生效。

    完整的示例見:官方Support庫Samples ($ANDROID_SDK/extras/android/support/samples/Support7Demos)

    More Tips

    列表無序的情況,可以用其id或原始數據List的index來比較排序,只要確保能正確實現compare即可
    如無需批量更新,或無頻繁的增刪改,其實用前面的ListAdapter比較好。
    總之:如果你的列表需要批量更新或者頻繁刪改,且剛好有明確的先后順序,快使用SortedList。

    總結

    以上是生活随笔為你收集整理的RecyclerView的优化:RecycledViewPool的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。