Android中的RecyclerView詳解

RecyclerView是什麼

官方解釋以下:A flexible view for providing a limited window into a large data set. 意思就是說在一個有限的窗口中顯示大量的數據集.緩存

回顧一下之前咱們使用的ListView ListView的侷限性能優化

  • 只有縱向列表一種佈局
  • 沒有支持動畫的API
  • 接口設計和系統不一致
    • setOnItemClickListener()
    • setOnItemLongClickListener()
    • setSelection()
  • 沒有強制實現ViewHolder
  • 性能不如RecyclerView

使用RecyclerView的優點bash

  • 默認支持Linear, Grid, Staggered Grid三種佈局架構

  • 友好的ItemAnimator動畫APIapp

  • 強制實現ViewHolderide

  • 解耦架構設計佈局

  • 相比 ListView更好的性能 RecyclerView支持的佈局性能

RecyclerView Demo

ViewHolder到底是什麼?

ListView中getView暴露的問題fetch

@Override
    public View getView(int position, View convertView, ViewGroup parent) {
        if (convertView == null) {
            convertView = LayoutInflater.from(parent.getContext())
                    .inflate(R.layout.list_view_item, parent, false);
        }
        /**
         * 下面的代碼不管在convertView是否爲null都會執行
         */
        ImageView avatar = convertView.findViewById(R.id.user_avatar);
        TextView name = convertView.findViewById(R.id.user_name);
        TextView title = convertView.findViewById(R.id.user_title);

        User user = getItem(position);
        Glide.with(parent.getContext()).load(user.avatar).into(avatar);
        name.setText(user.name);
        title.setText(user.title);
        return convertView;
    }
複製代碼

上面的代碼在執行getView,每次都會去findViewById,若是view個數比較多findViewById次數就會增多,這樣顯然會下降效率. ViewHolder的出現就是爲了保存View引用的容器類,減小重複findViewById次數,下面來看看用ViewHolder如何優化上面的代碼.flex

public View getView(int position, View convertView, ViewGroup parent) {
        UserViewHolder holder;
        if (convertView == null) {
            convertView = LayoutInflater.from(parent.getContext())
                    .inflate(R.layout.list_view_item, parent, false);
            holder = new UserViewHolder(convertView);
            holder.avater = convertView.findViewById(R.id.user_avatar);
            holder.name = convertView.findViewById(R.id.user_name);
            holder.title = convertView.findViewById(R.id.user_title);
            convertView.setTag(holder);
        } else {
            holder = (UserViewHolder)convertView.getTag();
        }
        /**
         * 下面的代碼不管在convertView是否爲null都會執行
         */
        ImageView avatar = convertView.findViewById(R.id.user_avatar);
        TextView name = convertView.findViewById(R.id.user_name);
        TextView title = convertView.findViewById(R.id.user_title);

        User user = getItem(position);
        holder.title.setText(user.title);
        holder.name.setText(user.name);
        Glide.with(parent.getContext()).load(user.avatar).into(holder.avater);
        return convertView;
    }
複製代碼

ViewHolder和View的對應關係

RecyclerView緩存機制

在講解RecyclerView緩存機制以前先來看看ListView的緩存機制,它的緩存機制比RecyclerView簡單,可是大致思想是同樣的.

對應到屏幕上

RecyclerView的緩存機制

Scrap: 在屏幕內可視的Item。 Cache: 在屏幕外的Item ViewCacheExtension : 用戶自定義的緩存策略 RecycledViewPool : 被廢棄的itemview,髒數據,須要從新onBindViewHolder. 在屏幕上的

這裏須要注意的是這個Cache,它雖然是緩存,可是它緩存效果和Scarp效果是同樣的。例如你的Cache是2,你上滑動出去後,下滑回來的兩個item是不會再進行onBindViewHolder的. 這裏另外提一點的是: 列表中item/廣告的impression統計.

  • ListView經過getView統計
  • RecycleView經過onBindViewHolder()統計?可能錯誤!
  • 經過onViewAttachedToWindow()統計

你可能不知道的RecyclerView性能優化策略

第一點

不要在onBindViewHolder中設置監聽器,在onCreateViewHolder中設置監聽器.

第二點

LinearLayoutManager.setInitialPrefetchitemCount()

  • 用戶滑動到橫向滑動的item RecyclerView的時候,因爲須要建立更復雜的RecyclerView以及多個子view,可能會致使頁面卡頓
  • 因爲RenderThread的存在,RecyclerView會進行prefetch
  • LinearLayoutManager.setInitialPrefetchItemCount(橫向列表初次顯示可見的item個數) -- 只有LinearLayoutManager有這個API -- 只有潛逃在內部的RecyclerView纔會生效.
第三點

RecyclerView.setHasFixedSize()

何時用? 若是Adapter的數據變化不會致使RecyclerView的大小變化就能夠用 RecyclerView.setHasFixedSize(true)

第四點

多個RectclerView共用RecycledViewPool.

第五點

使用DiffUtil

ItemDecoration的做用.

1,畫分割線 2,高亮item 3,視覺上分組 recyclerview教程

相關文章
相關標籤/搜索