RecycleView 相关只是学习

1.什么是RecyclerView?adapter的作用是什么,几个方法是做什么用的?如何理解adapter订阅者模式?

  • RecyclerView .adapter --处理数据集合并负责绑定视图
  • ViewHolder --持有所有的用于绑定数据或者需要操作的view
  • LayoutManager --负责摆放视图等相关操作
  • itemDroitemDecoration --负责绘制item附近的分割线
  • ItemItemAnimation -- 为item 的一般操作添加动画效果 如 增删条目等

RecyclerView.adapter 

① 根据不同的ViewType创建与之对应的item-Layout

② 访问数据集合并将数据绑定到正确的view上

几个方法的作用

onCreateViewViewHolder(ViewGroup parent ,int viewType)   --创建Item视图,并放回相应的ViewHolder

onBindViewHolder(VH holder ,int position)--绑定数据到正确的item上

getItemCount() --返回该item所持有的数量

getItemViewType(int position) --用来获取当前项Item(int position) 是那种类型的布局

adapter订阅者模式

当数据集合发生改变时,我们可以通过调用.notifyDataSetChanged(),来刷新列表,因为这样会触发列表重绘

订阅者模式:a:.notifyDataSetChanged()源码

public final void notifyDataSetChanged() {
    mObservable.notifyChanged();
}

b.接着查看.notifyChanged();源码

被观察者AdapterDataObservable,内部持有观察者AdapterDataObserver集合

static class AdapterDataObservable extends Observable<AdapterDataObserver> {

    public boolean hasObservers() {
        return !mObservers.isEmpty();
    }


    public void notifyChanged() {
        for (int i = mObservers.size() - 1; i >= 0; i--) {
            mObservers.get(i).onChanged();
        }
    }


    public void notifyItemRangeChanged(int positionStart, int itemCount) {

        notifyItemRangeChanged(positionStart, itemCount, null);

    }


    public void notifyItemRangeChanged(int positionStart, int itemCount, Object payload) {
        for (int i = mObservers.size() - 1; i >= 0; i--) {
            mObservers.get(i).onItemRangeChanged(positionStart, itemCount, payload);
        }

    }


    public void notifyItemRangeInserted(int positionStart, int itemCount) {
        for (int i = mObservers.size() - 1; i >= 0; i--) {
            mObservers.get(i).onItemRangeInserted(positionStart, itemCount);
        }

    }

}

观察者AdapterDataObserver,具体实现为RecyclerViewDataObserver,当数据源发生变更时,及时响应界面变化

public static abstract class AdapterDataObserver {
    public void onChanged() {
        // Do nothing
    }
    public void onItemRangeChanged(int positionStart, int itemCount) {
        // do nothing
    }
    public void onItemRangeChanged(int positionStart, int itemCount, Object payload) {
        onItemRangeChanged(positionStart, itemCount);
    }

}

c.接着查看setAdapter()源码中的setAdapterInternal(adapter, false, true)方法

public void setAdapter(Adapter adapter) {
    // bail out if layout is frozen
    setLayoutFrozen(false);
    setAdapterInternal(adapter, false, true);
    requestLayout();
}

setAdapterInternal(adapter, false, true)源码

private void setAdapterInternal(Adapter adapter, boolean compatibleWithPrevious,
        boolean removeAndRecycleViews) {
    if (mAdapter != null) {
        mAdapter.unregisterAdapterDataObserver(mObserver);
        mAdapter.onDetachedFromRecyclerView(this);
    }
    if (!compatibleWithPrevious || removeAndRecycleViews) {
        removeAndRecycleViews();
    }
    mAdapterHelper.reset();
    final Adapter oldAdapter = mAdapter;
    mAdapter = adapter;
    if (adapter != null) {
        //注册一个观察者RecyclerViewDataObserver
        adapter.registerAdapterDataObserver(mObserver);
        adapter.onAttachedToRecyclerView(this);
    }
    if (mLayout != null) {
        mLayout.onAdapterChanged(oldAdapter, mAdapter);
    }
    mRecycler.onAdapterChanged(oldAdapter, mAdapter, compatibleWithPrevious);
    mState.mStructureChanged = true;
    markKnownViewsInvalid();
}

当数据变更时,调用notify**方法时,Adapter内部的被观察者会遍历通知已经注册的观察者的对应方法,这时界面就会响应变更。

2. ViewHolder的作用是什么?如何理解ViewHolder的复用?什么时候停止调用onCreateViewHolder?

ViewHolder作用:

  1. adapter拥有ViewHolder的子类,且ViewHolder内部存储子View,避免耗时的findViewById的操作
  2. recyclerView定义的内部类包含很多属性种类多,使用场景也很多,经常使用到的onCreateViewHolder和onBindViewHolder方法,onCreateViewHolder()在recyclerViewHolder中需要一个新类型,item的ViewHolder调用时创建一个ViewHolder,而onBindViewHolder则需要recyclerView在特定位置的item展示数据时调用

ViewHolder复用:就是复写onCreateViewHolder 和onBindViewHolder的方法

3. ViewHolder中为何使用SparseArray替代HashMap存储viewId?

hashmapHashMap.Entry的数组,entry类可以包含的字段

  1. 一个非基本数据类型key
  2. 一个非基本数据类型的value
  3. 保存对象的哈希值
  4. 指向下一个entry的指针

当有键值对插入时,键的哈希值会被计算出来,这个值会被赋给entry类的hashcode变量,使用这个哈希值找到它将要被存入的数组中“”的索引

在Android 中 涉及都快速响应的应用时,持续的分发和释放内存会触发垃圾回收机制,因此会拖慢引用运行,而垃圾回收机制会影响应用性能表现,回收时间段内,应用不会运行,因此会造成应用卡顿

sparseArray:使用两个数组int[] keys 和 object[] values,来存储key和value 

相较于hashmap,舍弃了entry和object类型的key,放弃hashcode并使用二分法查找,在添加和操作的时候有更好的性能

4. LayoutManager作用是什么?LayoutManager样式有哪些?setLayoutManager源码里做了什么?

layoutManager 作用:拜访item位置,并负责决定何时回收和重用item ,recyclerView  允许自定义规则去放置view,控制者就是layoutManager,RecyclerView要展示内容,就必须设置layoutManager

layoutManager样式: 

  1. LinearLayoutManager  --水平或垂直item视图
  2. GridLayoutManager    --网格item视图
  3. StaggeredGridLayoutManager  --交错item视图

setLayoutManager 源码

public void setLayoutManager(LayoutManager layout) {
    if (layout == mLayout) {
        return;
    }
    // 停止滑动
    stopScroll();
    if (mLayout != null) {
        // 如果有动画,则停止所有的动画
        if (mItemAnimator != null) {
            mItemAnimator.endAnimations();
        }
        // 移除并回收视图
        mLayout.removeAndRecycleAllViews(mRecycler);
        // 回收废弃视图
        mLayout.removeAndRecycleScrapInt(mRecycler);
        //清除mRecycler
        mRecycler.clear();
        if (mIsAttached) {
            mLayout.dispatchDetachedFromWindow(this, mRecycler);
        }
        mLayout.setRecyclerView(null);
        mLayout = null;
    } else {
        mRecycler.clear();
    }
    mChildHelper.removeAllViewsUnfiltered();
    mLayout = layout;
    if (layout != null) {
        if (layout.mRecyclerView != null) {
            throw new IllegalArgumentException("LayoutManager " + layout +
                    " is already attached to a RecyclerView: " + layout.mRecyclerView);
        }
        mLayout.setRecyclerView(this);
        if (mIsAttached) {
            mLayout.dispatchAttachedToWindow(this);
        }
    }
    //更新新的缓存数据
    mRecycler.updateViewCacheSize();
    //重新请求 View 的测量、布局、绘制
    requestLayout();
}

如果之前设置过LayoutManager,移除之前的视图并缓存视图在recyclerView ,将新的mLayout对象与recyclerView绑定,更新缓存view的数量,最后调用requestLayout重新请求measure 、layout 、draw

5. SnapHelper主要是做什么用的?SnapHelper是怎么实现支持RecyclerView的对齐方式?

6. SpanSizeLookup的作用是干什么的?SpanSizeLookup如何使用?SpanSizeLookup实现原理如何理解?

请参考:https://juejin.im/post/5cce410551882541e40e471d

8. 上拉加载更多的功能是如何做的?添加滚动监听事件需要注意什么问题?网格布局上拉加载如何优化?

上拉加载功能:

  1. 添加recyclerView滑动事件:设置滑动监听,RecyclerView自带scrollListener,获取最后一个完全显示的itemposition,然后判断是否滑动到了最后一个
  2. 上拉加载分页数据:更新上拉加载更多数据的方法,可以使用notifyItemRangeInserted方法,
  3. 设置底部上拉加载footer布局:在adapter中可以上拉加载时处理footView 的逻辑
  4. 显示和隐藏footer布局

网格布局上拉加载优化:在adapter的onAtteronAttachedToRecycleView方法中处理网格布局情况。逻辑如果当前是footer的位置,该item占据两个单元格,正常情况下是占据一个单元格

@Override
public void onAttachedToRecyclerView(@NonNull RecyclerView recyclerView) {
    super.onAttachedToRecyclerView(recyclerView);
    RecyclerView.LayoutManager manager = recyclerView.getLayoutManager();
    if (manager instanceof GridLayoutManager) {
        final GridLayoutManager gridManager = ((GridLayoutManager) manager);
        gridManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
            @Override
            public int getSpanSize(int position) {
                // 如果当前是footer的位置,那么该item占据2个单元格,正常情况下占据1个单元格
                return getItemViewType(position) == footType ? gridManager.getSpanCount() : 1;
            }
        });
    }
}

如何实现自动进行上拉刷新?设置滑动监听,判断是否滑动到底部,是否是最后一条数据,如果是开始加载下一页数据,并且显示加载下一页loading,当加载数据成功后,隐藏该布局

如何实现手动上拉刷新?当滑动到最后一条数据时,显示加载更多布局,然后设置它的点击事件,点击之后开始加载下一页数据,加载完成后隐藏该布局

9. RecyclerView绘制原理如何理解?性能优化本质是什么?RecyclerView绘制原理过程大概是怎样的?

10 RecyclerView的Recyler是如何实现ViewHolder的缓存?如何理解recyclerView三级缓存是如何实现的?

public final class Recycler {
    final ArrayList<ViewHolder> mAttachedScrap = new ArrayList<>();
    ArrayList<ViewHolder> mChangedScrap = null;
    final ArrayList<ViewHolder> mCachedViews = new ArrayList<ViewHolder>();
    private final List<ViewHolder>
            mUnmodifiableAttachedScrap = Collections.unmodifiableList(mAttachedScrap);
    private int mRequestedCacheMax = DEFAULT_CACHE_SIZE;
    int mViewCacheMax = DEFAULT_CACHE_SIZE;
    RecycledViewPool mRecyclerPool;
    private ViewCacheExtension mViewCacheExtension;
    static final int DEFAULT_CACHE_SIZE = 2;
}

三级缓存实现:recyclerView在设计的时候对象分为了三级,每次创建ViewHolder的时候,会按照优先级依次查询缓存创建ViewHolder。

  • 一级缓存:返回布局和内容都有效的ViewHolder
    1. 按照position或者id进行匹配
    2. 一级缓存无效onCreateViewHolder和onBindViewHolder
    3. onAttachedScrap 在adapter.noti..的时候调用
    4. mChangedScrap 在每次View绘制的时候用到,getViewHolderForPosition非调用多次
    5. mCamCachedView :用来解决滑动抖动的情况,默认值为2
  • 二级缓存:返回view
    1. 按照position或者type匹配
    2. 直接返回view
    3. 需要继承自己的viewCacheExtention实现
    4. 位置固定,内容不发生改变情况,比如说headr如果内容固定,就可以使用
  • 三集缓存:返回布局有效,内容无效的ViewHolder
    1. 按照type进行匹配,type默认值为5
    2. layout是有效的,但内容是无效的
    3. 多个recyclerView可共享,可用于多个recyclerView的优化

11 屏幕滑动(状态是item状态可见,不可见,即将可见变化)时三级缓存是如何理解的?adapter中的几个方法是如何变化?

12 SnapHelper有哪些重要的方法,其作用就是是什么?LinearSnapHelper中是如何实现滚动停止的?

13 如何实现可以设置分割线的颜色,宽度,以及到左右两边的宽度间距的自定义分割线,说一下思路?

14 如何实现复杂type首页需求?如果不封装会出现什么问题和弊端?如何提高代码的简便性和高效性?

15 关于item条目点击事件在onCreateViewHolder中写和在onBindViewHolder中写有何区别?如何优化?

16 RecyclerView滑动卡顿原因有哪些?如何解决嵌套布局滑动冲突?如何解决RecyclerView实现画廊卡顿?

  滑动卡顿原因:

  • 嵌套布局滑动冲突:子控件消费了滑动事件,父控件就不会在处理这个事件,如果内部滑动控件消费了滑动操作,外部的滑动操作将不会执行
  • 嵌套布局层次太深:过度测量和过度绘制
  • recyclerView实现画廊,加载大图,如果快速滑动,会出现卡顿现象,主要是加载图片需要时间,
  • onCreateViewHolder和onBindViewHolder中进行了耗时操作

解决滑动冲突:可参考

https://github.com/yangchong211/YCBlogs/blob/master/android/recyclerView/23.RecyclerView%E6%BB%91%E5%8A%A8%E5%86%B2%E7%AA%81.md

https://www.jianshu.com/p/5dfc90656665

17 RecyclerView常见的优化有哪些?实际开发中都是怎么做的,优化前后对比性能上有何提升

优化:

  1. DiffUtil优化:分页拉取远端数据,并对数据进行缓存,提升二次加载速度,对于新增或删除的数据通过DiffUtil进行局部刷新
  2. 布局优化: 减少item文件inflate
  3. 减少view对象的创建
  4. 对itemView中子View的点击事件进行优化

18 如何解决RecyclerView嵌套RecyclerView条目自动上滚的Bug?如何解决ScrollView嵌套RecyclerView滑动冲突

  • recyclerView去除焦点
    recyclerview.setFocusableInTouchMode(false);
    recyclerview.requestFocus();

     

  • 直接在父布局中添加descendantFocusability属性 :android:descendantFocusability="beforeDescendants"
    • beforeDescendants:viewgroup会优先其子类控件而获取到焦点

      afterDescendants:viewgroup只有当其子类控件不需要获取焦点时才获取焦点

      blocksDescendants:viewgroup会覆盖子类控件而直接获得焦点

 

 

 

 

参考文献:https://juejin.im/post/5cce410551882541e40e471d

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
RecycleView 是一个用于在 Android 应用中展示大量数据的高效视图组件。它可以用于显示列表、网格或瀑布流等不同类型的布局,并支持高度的重用和回收。这个组件可以大大提高应用程序的性能,因为它只会在屏幕上显示可见项,而不是将所有数据一次性加载到内存中。 使用 RecycleView,您需要创建一个适配器(Adapter)来将数据绑定到视图上,并且可以自定义视图的外观和交互。您可以使用默认的适配器(如 ArrayAdapter)或自定义适配器来满足特定的需求。 以下是一个示例代码,演示如何使用 RecycleView 在一个简单的列表中显示一组文本项: ```java public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> { private List<String> mData; public MyAdapter(List<String> data) { mData = data; } @Override public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_layout, parent, false); return new ViewHolder(view); } @Override public void onBindViewHolder(ViewHolder holder, int position) { String item = mData.get(position); holder.textView.setText(item); } @Override public int getItemCount() { return mData.size(); } public static class ViewHolder extends RecyclerView.ViewHolder { public TextView textView; public ViewHolder(View itemView) { super(itemView); textView = itemView.findViewById(R.id.text_view); } } } ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值