ListView和RecycleView
ListView
使用步骤可看Android基础------ListView,其setAdapter()如下,回调getCount()获取Item个数
@Override
public void setAdapter(ListAdapter adapter) {
if (mAdapter != null && mDataSetObserver != null) {
mAdapter.unregisterDataSetObserver(mDataSetObserver);
}
resetList();
mRecycler.clear();
if (mHeaderViewInfos.size() > 0|| mFooterViewInfos.size() > 0) {
mAdapter = wrapHeaderListAdapterInternal(mHeaderViewInfos, mFooterViewInfos, adapter);
} else {
mAdapter = adapter;
}
......
super.setAdapter(adapter);
if (mAdapter != null) {
......
mItemCount = mAdapter.getCount();
checkFocus();
mDataSetObserver = new AdapterDataSetObserver();
mAdapter.registerDataSetObserver(mDataSetObserver);
......
}......
requestLayout();
}
创建AdapterDataSetObserver,调用ListAdapter的registerDataSetObserver(),其实现类是BaseAdapter
private final DataSetObservable mDataSetObservable = new DataSetObservable();
public void registerDataSetObserver(DataSetObserver observer) {
mDataSetObservable.registerObserver(observer);
}
public void unregisterDataSetObserver(DataSetObserver observer) {
mDataSetObservable.unregisterObserver(observer);
}
public void notifyDataSetChanged() {
mDataSetObservable.notifyChanged();
}
当调用notifyDataSetChanged()时会回调AdapterDataSetObserver的notifyChanged(),其在ListView的父类AbsListView里面
class AdapterDataSetObserver extends AdapterView<ListAdapter>.AdapterDataSetObserver {
@Override
public void onChanged() {
super.onChanged();
......
}
......
}
调用AdapterView的AdapterDataSetObserver的notifyChanged()
class AdapterDataSetObserver extends DataSetObserver {
......
@Override
public void onChanged() {
mDataChanged = true;
mOldItemCount = mItemCount;
mItemCount = getAdapter().getCount();
......
checkFocus();
requestLayout();
}
......
}
调用requestLayout()会重新布局,调用AdapterView的onLayout()
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
super.onLayout(changed, l, t, r, b);
......
layoutChildren();
......
}
调用ListView的layoutChildren(),根据mLayoutMode设置布局方式
@Override
protected void layoutChildren() {
final boolean blockLayoutRequests = mBlockLayoutRequests;
if (blockLayoutRequests) {
return;
}
mBlockLayoutRequests = true;
try {
super.layoutChildren();
invalidate();
......
switch (mLayoutMode) {
......
case LAYOUT_FORCE_BOTTOM:
sel = fillUp(mItemCount - 1, childrenBottom);
adjustViewsUpOrDown();
break;
case LAYOUT_FORCE_TOP:
mFirstPosition = 0;
sel = fillFromTop(childrenTop);
adjustViewsUpOrDown();
break;
......
}......
}
}
调用ListView的fillFromTop()会调用fillDown()从上到下布局,若不到底部且小于总数,则循环创建ItemView
private View fillDown(int pos, int nextTop) {
View selectedView = null;
int end = (mBottom - mTop);
if ((mGroupFlags & CLIP_TO_PADDING_MASK) == CLIP_TO_PADDING_MASK) {
end -= mListPadding.bottom;
}
while (nextTop < end && pos < mItemCount) {
boolean selected = pos == mSelectedPosition;
View child = makeAndAddView(pos, nextTop, true, mListPadding.left, selected);
nextTop = child.getBottom() + mDividerHeight;
if (selected) {
selectedView = child;
}
pos++;
}
setVisibleRangeHint(mFirstPosition, mFirstPosition + getChildCount() - 1);
return selectedView;
}
private View makeAndAddView(int position, int y, boolean flow, int childrenLeft, boolean selected) {
......
final View child = obtainView(position, mIsScrap);
setupChild(child, position, y, flow, childrenLeft, selected, mIsScrap[0]);
return child;
}
调用AdapterView的obtainView(),这里会回调getItemViewType()、getView()
View obtainView(int position, boolean[] outMetadata) {
......
final View transientView = mRecycler.getTransientStateView(position); //从缓存列表mTransientStateViews指定位置获取Item
if (transientView != null) {
final LayoutParams params = (LayoutParams) transientView.getLayoutParams();
if (params.viewType == mAdapter.getItemViewType(position)) { //若ViewType没变则回调getView()获取View重新绑定数据
final View updatedView = mAdapter.getView(position, transientView, this);
if (updatedView != transientView) { //若没有复用,返回的不是同一个View,则添加到ScrapView
setItemViewLayoutParams(updatedView, position);
mRecycler.addScrapView(updatedView, position);
}
}
......
return transientView;
}
final View scrapView = mRecycler.getScrapView(position); //若不在缓存列表,取出ScrapView列表对应位置的scrapView
final View child = mAdapter.getView(position, scrapView, this); //回调getView()获取child,若scrapView为空则返回新的View,若不为空也可能返回的不是同一个View,如Header
if (scrapView != null) {
if (child != scrapView) { //若scrapView和child不一样,说明是新的View,将scrapView添加到缓存列表mTransientStateViews
mRecycler.addScrapView(scrapView, position);
}......
}
......
setItemViewLayoutParams(child, position);
......
return child;
}
以下面代码为例
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder = null;
if (convertView == null) {
holder = new ViewHolder();
convertView = mInflater.inflate(R.layout.list_item, null);
holder.dataIv = convertView.findViewById(R.id.list_iv);
holder.dataTv = convertView.findViewById(R.id.list_tv);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
Data data = (Data) getItem(position);
holder.dataIv.setImageResource(data.getImageId());
holder.dataTv.setText(data.getName());
return convertView;
}
- 第一次创建时convertView为空,会创建铺满屏幕个数的Item+1,如下图为8个
- 当滑动时将Item1缓存起来,并赋值给convertView,下一个Item9就会复用Item1重新绑定数据
RecycleView
使用步骤可看Android基础------RecycleView
- onCreateViewHolder()、onBindViewHolder()相当于ListView的getView()
- 操作对象变成ViewHolder,无需像ListView那样判断缓存
其setAdapter()方法如下
public void setAdapter(@Nullable Adapter adapter) {
setLayoutFrozen(false);
setAdapterInternal(adapter, false, true);
processDataSetCompletelyChanged(false);
requestLayout();
}
private void setAdapterInternal(@Nullable 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) {
adapter.registerAdapterDataObserver(mObserver);
adapter.onAttachedToRecyclerView(this);
}
if (mLayout != null) {
mLayout.onAdapterChanged(oldAdapter, mAdapter);
}
mRecycler.onAdapterChanged(oldAdapter, mAdapter, compatibleWithPrevious);
mState.mStructureChanged = true;
}
将RecyclerViewDataObserver注册到RecyclerViewAdapter,当调用notifyDataSetChanged()会回调onChanged()重新布局
private final RecyclerViewDataObserver mObserver = new RecyclerViewDataObserver();
public final void notifyDataSetChanged() {
mObservable.notifyChanged();
}
private class RecyclerViewDataObserver extends AdapterDataObserver {
......
@Override
public void onChanged() {
......
if (!mAdapterHelper.hasPendingUpdates()) {
requestLayout();
}
}
......
}
requestLayout()会调用onLayout()、dispatchLayout()、dispatchLayoutStep1()
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
......
dispatchLayout();
......
}
void dispatchLayout() {
......
if (mState.mLayoutStep == State.STEP_START) {
dispatchLayoutStep1();
mLayout.setExactMeasureSpecsFrom(this);
dispatchLayoutStep2();
}......
dispatchLayoutStep3();
}
private void dispatchLayoutStep1() {
......
if (mState.mRunPredictiveAnimations) {
......
mLayout.onLayoutChildren(mRecycler, mState);
......
}
......
}
mLayout通过setLayoutManager()设置
public void setLayoutManager(@Nullable LayoutManager layout) {
if (layout == mLayout) {
return;
}
......
mLayout = layout;
if (layout != null) {
......
mLayout.setRecyclerView(this);
if (mIsAttached) {
mLayout.dispatchAttachedToWindow(this);
}
}
mRecycler.updateViewCacheSize();
requestLayout();
}
以LinearLayoutManager的onLayoutChildren()为例
public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state){
......
if (mAnchorInfo.mLayoutFromEnd) {
......
} else {
......
fill(recycler, mLayoutState, state, false);
......
}
......
}
int fill(RecyclerView.Recycler recycler, LayoutState layoutState, RecyclerView.State state, boolean stopOnFocusable) {
......
int remainingSpace = layoutState.mAvailable + layoutState.mExtraFillSpace; //计算当前可用空间
LayoutChunkResult layoutChunkResult = mLayoutChunkResult;
while ((layoutState.mInfinite || remainingSpace > 0) && layoutState.hasMore(state)) {
......
layoutChunk(recycler, state, layoutState, layoutChunkResult); //若还有空间则循环布局Item
......
}
......
return start - layoutState.mAvailable;
}
void layoutChunk(RecyclerView.Recycler recycler, RecyclerView.State state, LayoutState layoutState, LayoutChunkResult result) {
View view = layoutState.next(recycler); //获取View
......
RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) view.getLayoutParams(); //获取LayoutParams
......
measureChildWithMargins(view, 0, 0); //测量View
result.mConsumed = mOrientationHelper.getDecoratedMeasurement(view); //计算消耗的宽高
int left, top, right, bottom; //计算上下左右坐标
if (mOrientation == VERTICAL) {
if (isLayoutRTL()) {
right = getWidth() - getPaddingRight();
left = right - mOrientationHelper.getDecoratedMeasurementInOther(view);
} else {
left = getPaddingLeft();
right = left + mOrientationHelper.getDecoratedMeasurementInOther(view);
}
if (layoutState.mLayoutDirection == LayoutState.LAYOUT_START) {
bottom = layoutState.mOffset;
top = layoutState.mOffset - result.mConsumed;
} else {
top = layoutState.mOffset;
bottom = layoutState.mOffset + result.mConsumed;
}
}......
layoutDecoratedWithMargins(view, left, top, right, bottom); //调用layout()
......
result.mFocusable = view.hasFocusable();
}
public void layoutDecoratedWithMargins(@NonNull View child, int left, int top, int right, int bottom) {
final LayoutParams lp = (LayoutParams) child.getLayoutParams();
final Rect insets = lp.mDecorInsets;
child.layout(left + insets.left + lp.leftMargin, top + insets.top + lp.topMargin,
right - insets.right - lp.rightMargin,
bottom - insets.bottom - lp.bottomMargin);
}
View next(RecyclerView.Recycler recycler) {
......
final View view = recycler.getViewForPosition(mCurrentPosition);
mCurrentPosition += mItemDirection;
return view;
}
next()调用RecyclerView的getViewForPosition(),回调getItemViewType()
@NonNull
public View getViewForPosition(int position) {
return getViewForPosition(position, false);
}
View getViewForPosition(int position, boolean dryRun) {
return tryGetViewHolderForPositionByDeadline(position, dryRun, FOREVER_NS).itemView;
}
@Nullable
ViewHolder tryGetViewHolderForPositionByDeadline(int position, boolean dryRun, long deadlineNs) {
......
ViewHolder holder = null;
if (mState.isPreLayout()) {
holder = getChangedScrapViewForPosition(position);
......
}
if (holder == null) {
holder = getScrapOrHiddenOrCachedHolderForPosition(position, dryRun);
......
}
if (holder == null) {
final int offsetPosition = mAdapterHelper.findPositionOffset(position);
......
final int type = mAdapter.getItemViewType(offsetPosition);
if (mAdapter.hasStableIds()) {
holder = getScrapOrCachedViewForId(mAdapter.getItemId(offsetPosition), type, dryRun);
......
}
if (holder == null && mViewCacheExtension != null) {
......
final View view = mViewCacheExtension.getViewForPositionAndType(this, position, type);
if (view != null) {
holder = getChildViewHolder(view);
......
}
}
if (holder == null) {
......
holder = getRecycledViewPool().getRecycledView(type);
......
}
if (holder == null) { //上面是各种缓存都为空,才调用createViewHolder()
......
holder = mAdapter.createViewHolder(RecyclerView.this, type);
......
}
}
......
boolean bound = false;
if (mState.isPreLayout() && holder.isBound()) {
......
} else if (!holder.isBound() || holder.needsUpdate() || holder.isInvalid()) { //这里绑定数据
......
final int offsetPosition = mAdapterHelper.findPositionOffset(position);
bound = tryBindViewHolderByDeadline(holder, offsetPosition, position, deadlineNs);
}
......
return holder;
}
调用RecyclerView的createViewHolder()、tryBindViewHolderByDeadline()
@NonNull
public final VH createViewHolder(@NonNull ViewGroup parent, int viewType) {
try {
final VH holder = onCreateViewHolder(parent, viewType);
......
holder.mItemViewType = viewType;
return holder;
}......
}
private boolean tryBindViewHolderByDeadline(@NonNull ViewHolder holder, int offsetPosition, int position, long deadlineNs) {
......
mAdapter.bindViewHolder(holder, offsetPosition);
......
return true;
}
public final void bindViewHolder(@NonNull VH holder, int position) {
......
onBindViewHolder(holder, position, holder.getUnmodifiedPayloads());
......
}
public void onBindViewHolder(@NonNull VH holder, int position, @NonNull List<Object> payloads) {
onBindViewHolder(holder, position);
}