RecyclerView源码分析
来源:互联网 发布:网络贷款利息计算器 编辑:程序博客网 时间:2024/05/16 23:58
RecyclerView发布已经挺久了,博客上也有好多优秀的使用教程,相比较ListView,RecyclerView的使用确实更加灵活,本文就针对RecyclerView的源码进行分析,分析一下它的工作原理,关于它的使用教程,大家可以去看下hongyang大神的博文,以下我就自己针对源码的查看写了自己的分析,如有不对的地方,欢迎提出指教。
我们首先看下RecyclerView这个类的第一条注释说明:A flexible view for providing a limited window into a large data set.可见该View的定义就是一种灵活的、能够装载大量数据的View。该类的源码有1w多行,我们就从使用它相关的代码进行查看:
recyclerView = (RecyclerView) findViewById(R.id.id_recyclerview); recyclerView.setLayoutManager(new StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL)); recyclerView.setAdapter(new MyAdapter(this,datas)); recyclerView.addItemDecoration(new DividerItemDecoration(this, DividerItemDecoration.VERTICAL_LIST));
这是我们常用的一段基本的代码,可知,我们会用到以下几个方法:setLayoutManager,(关键点,灵活的设置布局,简单),setAdapter,addItemDecoration。另外,还有这个类我们也一起看下:Recycler。
关于Recycler:
A Recycler is responsible for managing scrapped or detached item views for reufinal
public final class Recycler { final ArrayList<ViewHolder> mAttachedScrap = new ArrayList<>(); private ArrayList<ViewHolder> mChangedScrap = null; final ArrayList<ViewHolder> mCachedViews = new ArrayList<ViewHolder>(); private final List<ViewHolder> mUnmodifiableAttachedScrap = Collections.unmodifiableList(mAttachedScrap); private int mViewCacheMax = DEFAULT_CACHE_SIZE; private RecycledViewPool mRecyclerPool; private ViewCacheExtension mViewCacheExtension; private static final int DEFAULT_CACHE_SIZE = 2;
它为RecyclerView中的item views提供了复用,用于管理已经废弃或与RecyclerView分离的(scrapped or detached)item view。
/** * Set the {@link LayoutManager} that this RecyclerView will use. * * <p>In contrast to other adapter-backed views such as {@link android.widget.ListView} * or {@link android.widget.GridView}, RecyclerView allows client code to provide custom * layout arrangements for child views. These arrangements are controlled by the * {@link LayoutManager}. A LayoutManager must be provided for RecyclerView to function.</p> * * <p>Several default strategies are provided for common uses such as lists and grids.</p> * * @param layout LayoutManager to use */ public void setLayoutManager(LayoutManager layout) { if (layout == mLayout) { return; } stopScroll(); // TODO We should do this switch a dispachLayout pass and animate children. There is a good // chance that LayoutManagers will re-use views. if (mLayout != null) { if (mIsAttached) { mLayout.dispatchDetachedFromWindow(this, mRecycler); } mLayout.setRecyclerView(null); } 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); } } requestLayout(); }
我们看这句代码:mLayout.setRecyclerView(this);
继续追踪下去:
/** * These measure specs might be the measure specs that were passed into RecyclerView's * onMeasure method OR fake measure specs created by the RecyclerView. * For example, when a layout is run, RecyclerView always sets these specs to be * EXACTLY because a LayoutManager cannot resize RecyclerView during a layout pass. */ private int mWidthSpec, mHeightSpec; void setRecyclerView(RecyclerView recyclerView) { if (recyclerView == null) { mRecyclerView = null; mChildHelper = null; mWidthSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.EXACTLY); mHeightSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.EXACTLY); } else { mRecyclerView = recyclerView; mChildHelper = recyclerView.mChildHelper; mWidthSpec = MeasureSpec .makeMeasureSpec(recyclerView.getWidth(), MeasureSpec.EXACTLY); mHeightSpec = MeasureSpec .makeMeasureSpec(recyclerView.getHeight(), MeasureSpec.EXACTLY); } }
也就是测量RecyclerView 中itemView高度和宽度,然后对其绘制,可以实现水平滚动、垂直滚动、方块表格等列表形式。具体可以看LayoutManager这个类。
接下来我们看下这句代码:
recyclerView.setAdapter(new MyAdapter(this,datas));
可知,它是为recyclerView存放数据集的,其中MyAdapter是我继承RecyclerView.Adapter
/** * Base class for an Adapter * * <p>Adapters provide a binding from an app-specific data set to views that are displayed * within a {@link RecyclerView}.</p> */ public static abstract class Adapter<VH extends ViewHolder> { private final AdapterDataObservable mObservable = new AdapterDataObservable(); private boolean mHasStableIds = false; /** * Called when RecyclerView needs a new {@link ViewHolder} of the given type to represent * an item. * <p> * This new ViewHolder should be constructed with a new View that can represent the items * of the given type. You can either create a new View manually or inflate it from an XML * layout file. * <p> * The new ViewHolder will be used to display items of the adapter using * {@link #onBindViewHolder(ViewHolder, int, List)}. Since it will be re-used to display * different items in the data set, it is a good idea to cache references to sub views of * the View to avoid unnecessary {@link View#findViewById(int)} calls. * * @param parent The ViewGroup into which the new View will be added after it is bound to * an adapter position. * @param viewType The view type of the new View. * * @return A new ViewHolder that holds a View of the given view type. * @see #getItemViewType(int) * @see #onBindViewHolder(ViewHolder, int) */ public abstract VH onCreateViewHolder(ViewGroup parent, int viewType); public abstract void onBindViewHolder(VH holder, int position); public void onBindViewHolder(VH holder, int position, List<Object> payloads) { onBindViewHolder(holder, position); } /** * This method calls {@link #onCreateViewHolder(ViewGroup, int)} to create a new * {@link ViewHolder} and initializes some private fields to be used by RecyclerView. * * @see #onCreateViewHolder(ViewGroup, int) */ public final VH createViewHolder(ViewGroup parent, int viewType) { TraceCompat.beginSection(TRACE_CREATE_VIEW_TAG); final VH holder = onCreateViewHolder(parent, viewType); holder.mItemViewType = viewType; TraceCompat.endSection(); return holder; } ......
我们可以重写该类的onBindViewHolder方法,进行自己的数据处理,而在onCreateViewHolder方法中我们可以读取item文件进行设置。相比ListView的优点就是RecyclerView直接将ViewHolder内置:
ViewHolder 部分代码:
/** * A ViewHolder describes an item view and metadata about its place within the RecyclerView. * * <p>{@link Adapter} implementations should subclass ViewHolder and add fields for caching * potentially expensive {@link View#findViewById(int)} results.</p> * * <p>While {@link LayoutParams} belong to the {@link LayoutManager}, * {@link ViewHolder ViewHolders} belong to the adapter. Adapters should feel free to use * their own custom ViewHolder implementations to store data that makes binding view contents * easier. Implementations should assume that individual item views will hold strong references * to <code>ViewHolder</code> objects and that <code>RecyclerView</code> instances may hold * strong references to extra off-screen item views for caching purposes</p> */ public static abstract class ViewHolder { public final View itemView; int mPosition = NO_POSITION; int mOldPosition = NO_POSITION; long mItemId = NO_ID; int mItemViewType = INVALID_TYPE; int mPreLayoutPosition = NO_POSITION; // The item that this holder is shadowing during an item change event/animation ViewHolder mShadowedHolder = null; // The item that is shadowing this holder during an item change event/animation ViewHolder mShadowingHolder = null; .......
提供了很多属性。
ItemDecoration:
/** * An ItemDecoration allows the application to add a special drawing and layout offset * to specific item views from the adapter's data set. This can be useful for drawing dividers * between items, highlights, visual grouping boundaries and more. * * <p>All ItemDecorations are drawn in the order they were added, before the item * views (in {@link ItemDecoration#onDraw(Canvas, RecyclerView, RecyclerView.State) onDraw()} * and after the items (in {@link ItemDecoration#onDrawOver(Canvas, RecyclerView, * RecyclerView.State)}.</p> */ public static abstract class ItemDecoration { /** * Draw any appropriate decorations into the Canvas supplied to the RecyclerView. * Any content drawn by this method will be drawn before the item views are drawn, * and will thus appear underneath the views. * * @param c Canvas to draw into * @param parent RecyclerView this ItemDecoration is drawing into * @param state The current state of RecyclerView */ public void onDraw(Canvas c, RecyclerView parent, State state) { onDraw(c, parent); } /** * @deprecated * Override {@link #onDraw(Canvas, RecyclerView, RecyclerView.State)} */ @Deprecated public void onDraw(Canvas c, RecyclerView parent) { } /** * Draw any appropriate decorations into the Canvas supplied to the RecyclerView. * Any content drawn by this method will be drawn after the item views are drawn * and will thus appear over the views. * * @param c Canvas to draw into * @param parent RecyclerView this ItemDecoration is drawing into * @param state The current state of RecyclerView. */ public void onDrawOver(Canvas c, RecyclerView parent, State state) { onDrawOver(c, parent); } /** * @deprecated * Override {@link #onDrawOver(Canvas, RecyclerView, RecyclerView.State)} */ @Deprecated public void onDrawOver(Canvas c, RecyclerView parent) { } /** * @deprecated * Use {@link #getItemOffsets(Rect, View, RecyclerView, State)} */ @Deprecated public void getItemOffsets(Rect outRect, int itemPosition, RecyclerView parent) { outRect.set(0, 0, 0, 0); } /** * Retrieve any offsets for the given item. Each field of <code>outRect</code> specifies * the number of pixels that the item view should be inset by, similar to padding or margin. * The default implementation sets the bounds of outRect to 0 and returns. * * <p> * If this ItemDecoration does not affect the positioning of item views, it should set * all four fields of <code>outRect</code> (left, top, right, bottom) to zero * before returning. * * <p> * If you need to access Adapter for additional data, you can call * {@link RecyclerView#getChildAdapterPosition(View)} to get the adapter position of the * View. * * @param outRect Rect to receive the output. * @param view The child view to decorate * @param parent RecyclerView this ItemDecoration is decorating * @param state The current state of RecyclerView. */ public void getItemOffsets(Rect outRect, View view, RecyclerView parent, State state) { getItemOffsets(outRect, ((LayoutParams) view.getLayoutParams()).getViewLayoutPosition(), parent); } }
像我们以前用ListView都是在ItemView中去写好布局,现在我们的ItemView和要装饰的UI是分离出来的,用ItemDecoration这个方法即可装饰ItemView,比如项之间的分割线、Margin、绘制颜色等。我们也可以自定义ItemDecoration引用自己绘制的UI进行使用,功能上更加强大。
- RecyclerView源码分析
- RecyclerView源码分析
- RecyclerView滑动源码分析
- Android RecyclerView源码分析
- RecyclerView源码分析
- RecyclerView源码分析
- RecyclerView源码分析
- RecyclerView源码分析
- RecyclerView 源码分析
- RecyclerView源码分析
- RecyclerView源码分析
- RecyclerView 源码分析
- RecyclerView 源码分析(一)
- Android中的RecyclerView源码分析
- RecyclerView ItemTouchHelper源码分析扩展
- Android recyclerview源码分析(一)
- Android recyclerview源码分析(二)
- recyclerview万能适配器用法以及源码分析
- Android Studio 实现使用AIDL的IPC通讯
- [iOS 扩展转] iOS扩展开发-Today扩展&share扩展
- MD5Util (MD5加密摘要算法)。
- centos安装配置svn
- SVN还原文件到历史版本详解
- RecyclerView源码分析
- 阈值化
- 剑指Offer:面试题12——打印1到最大的n位数(java实现)
- 定价类型更新
- UILable &UIImageView& UIButton布局
- C++中的宏定义
- 对快速排序的一些理解
- Jetty启动webApp报错,是因为没有加全依赖
- QT5,5 webview 刷新不出网页解决的办法