android RecyclerView浅谈
伴随着android 5.0的发布,系统为开发者提供了一个优化了的列表控件RecyclerView。RecyclerView支持横向和纵向的列表,不止如此,还支持普通的GridView列表和交叉排列的GridView列表,它依靠LayoutManager的子类来控制自身的方向,功能丰富强大。
LayoutManager同时负责了对RecyclerView的测绘以及对Item view的定位,并提实现了列表的滚动和Item View 的回收利用;开发者可以通过继承LayoutManager,实现高级的View列表。
RecyclerView直接继承了ViewGroup,ListView则是继承了AbListView,ListView是间接继承了ViewGroup;二者实现的原理是一样的,只是RecyclerView做了更多的优化。RecyclerView规范了ViewHolder的写法,同时内部做了大量的优化,性能相比ListView有很大提升。
1、自开发者调用RecyclerView.setAdapter(),这时会替换掉旧的Adapter,并向ViewRoot申请(requestLayout),对RecyclerView进行重绘。
2、ViewRoot收到重绘请求,开始对View树进行重绘,重绘的过程是重新测量的宽高并(measure),重新进行布局(layout);重新layout的过程会调用RecyclerView.onLayout()。
3、RecyclerView.onLayout()会对Item View 进行位置摆放,layout内部的dispatchLayout()此时将布局过程交给了LayoutManager。
4、LayoutManger通过onLayoutChildren()>>>>fill()>>> layoutChunk()>>>next(),最终调用RecyclerView.Recycler.getViewForPosition()。
方法内部步骤(getViewForPosition):
第一步:从已经回收的ViewHolder列表中,寻找合适的ViewHolder来复用,如果ViewHolder不可用,就销毁ViewHolder并将ViewHolder置Null;如果ViewHolder不可用执行第二步。
第二步:按位置去ViewHolder回收列表中找的ViewHolder,如果ViewHolder不可用执行第三步。
第三步:调用Adapter.createViewHolder()创建新的ViewHolder。
View getViewForPosition(int position, boolean dryRun) {
3262 if (position < 0 || position >= mState.getItemCount()) {
3263 throw new IndexOutOfBoundsException("Invalid item position " + position
3264 + "(" + position + "). Item count:" + mState.getItemCount());
3265 }
3266 boolean fromScrap = false;
3267 ViewHolder holder = null;
3268 // 0) If there is a changed scrap, try to find from there
3269 if (mState.isPreLayout()) {
3270 holder = getChangedScrapViewForPosition(position);
3271 fromScrap = holder != null;
3272 }
3273 // 1) Find from scrap by position
3274 if (holder == null) {
3275 holder = getScrapViewForPosition(position, INVALID_TYPE, dryRun);
3276 若干回收细节
3290 }
3291 holder = null;
3292 } else {
3293 fromScrap = true;
3294 }
3295 }
3296 }
3297 if (holder == null) {
3298 final int offsetPosition = mAdapterHelper.findPositionOffset(position);
3305 final int type = mAdapter.getItemViewType(offsetPosition);
3306 // 2) Find from scrap via stable ids, if exists
3307 if (mAdapter.hasStableIds()) {
3308 holder = getScrapViewForId(mAdapter.getItemId(offsetPosition), type, dryRun);
3309 if (holder != null) {
3310 // update position
3311 holder.mPosition = offsetPosition;
3312 fromScrap = true;
3313 }
3314 }
3348 if (holder == null) {
3349 holder = mAdapter.createViewHolder(RecyclerView.this,
3350 mAdapter.getItemViewType(offsetPosition));
3351 if (DEBUG) {
3352 Log.d(TAG, "getViewForPosition created new ViewHolder");
3353 }
3354 }
3355 }
3356
3388 }
3389