您的位置:首页 > 移动开发 > Android开发

Android ListView初始化简单分析

2015-07-18 18:46 453 查看
下面是分析ListView初始化的源码流程分析,主要是ListVIew.onLayout过程与普通视图的layout过程完全不同,避免流程交代不清楚,以下是一个流程的思维导图。

思维导图是顺序是从左向右,从上向下。



一、 先看构造函数,上图中1.1就不分析了,主要是读取一些ListView参数,直接来看1.2 ViewGroup构造函数源码

[java] view
plaincopyprint?

private void initViewGroup() {

......

// 初始化保存当前ViewGroup中所有View的数组

mChildren = new View[ARRAY_INITIAL_CAPACITY];

// 初始时其Child个数为0

mChildrenCount = 0;

......

}

视图的创建过程的都会执行的三个步骤: onMeasure, onLayout, onDraw

二、接着2 即 ListView.onMeasure方法,只是获取当前ListView的宽高

[java] view
plaincopyprint?

@Override

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

// Sets up mListPadding

super.onMeasure(widthMeasureSpec, heightMeasureSpec);

// 获取当前ListView总宽高

int widthSize = MeasureSpec.getSize(widthMeasureSpec);

int heightSize = MeasureSpec.getSize(heightMeasureSpec);

......

setMeasuredDimension(widthSize , heightSize);

mWidthMeasureSpec = widthMeasureSpec;

}

三、步骤3是重点,AbsListView.onLayout的流程与普通View的不同

[java] view
plaincopyprint?

@Override

protected void onLayout(boolean changed, int l, int t, int r, int b) {

super.onLayout(changed, l, t, r, b);

mInLayout = true;

// 初始时changed = true

if (changed) {

int childCount = getChildCount();

for (int i = 0; i < childCount; i++) {

// ?

getChildAt(i).forceLayout();

}

mRecycler.markChildrenDirty();

}

if (mFastScroller != null && mItemCount != mOldItemCount) {

mFastScroller.onItemCountChanged(mOldItemCount, mItemCount);

}

// ListView实现此方法

layoutChildren();

mInLayout = false;

mOverscrollMax = (b - t) / OVERSCROLL_LIMIT_DIVISOR;

}

四、步骤4.1 具体分析ListVIew.layoutChildren

[java] view
plaincopyprint?

@Override

protected void layoutChildren() {

// 默认为false

final boolean blockLayoutRequests = mBlockLayoutRequests;

if (!blockLayoutRequests) {

// 目的是为了阻止没必要的layout操作,提交效率

mBlockLayoutRequests = true;

} else {

return;

}

try {

super.layoutChildren();

// 为什么此处要请求重绘?

invalidate();

......

int childCount = getChildCount();

......

boolean dataChanged = mDataChanged;

if (dataChanged) {

handleDataChanged();

}

......

// 把所有child view放置到RecycleBin

// 满足条件的话可以重用这些child view

final int firstPosition = mFirstPosition;

// ListView中Item复用使用此数据结构

final RecycleBin recycleBin = mRecycler;

// reset the focus restoration

View focusLayoutRestoreDirectChild = null;

// Don't put header or footer views into the Recycler. Those are

// already cached in mHeaderViews;

if (dataChanged) {

for (int i = 0; i < childCount; i++) {

recycleBin.addScrapView(getChildAt(i), firstPosition+i);

}

} else {

// 创建childCount个数的View放入RecycleBin类activeViews数组中

recycleBin.fillActiveViews(childCount, firstPosition);

}

......

// Clear out old views

detachAllViewsFromParent();

recycleBin.removeSkippedScrap();

switch (mLayoutMode) {

......

default:

if (childCount == 0) {

if (!mStackFromBottom) {

final int position = lookForSelectablePosition(0, true);

setSelectedPositionInt(position);

// 此方法是重点,以下具体分析

sel = fillFromTop(childrenTop);

} else {

final int position = lookForSelectablePosition(mItemCount - 1, false);

setSelectedPositionInt(position);

sel = fillUp(mItemCount - 1, childrenBottom);

}

} else {

if (mSelectedPosition >= 0 && mSelectedPosition < mItemCount) {

sel = fillSpecific(mSelectedPosition,

oldSel == null ? childrenTop : oldSel.getTop());

} else if (mFirstPosition < mItemCount) {

sel = fillSpecific(mFirstPosition,

oldFirst == null ? childrenTop : oldFirst.getTop());

} else {

sel = fillSpecific(0, childrenTop);

}

}

break;

}

// Flush any cached views that did not get reused above

recycleBin.scrapActiveViews();

......

invokeOnItemScrollListener();

} finally {

if (!blockLayoutRequests) {

mBlockLayoutRequests = false;

}

}

五、 分析步骤4.2 ListView.fillFromTop源码

[java] view
plaincopyprint?

// 从上向下在ListView中填充Item View

private View fillFromTop(int nextTop) {

mFirstPosition = Math.min(mFirstPosition, mSelectedPosition);

mFirstPosition = Math.min(mFirstPosition, mItemCount - 1);

if (mFirstPosition < 0) {

mFirstPosition = 0;

}

// 具体操作在此

return fillDown(mFirstPosition, nextTop);

}

六、查看步骤4.3 ListView.fillDown源码

[java] view
plaincopyprint?

// 在参数pos下面填充Item View

private View fillDown(int pos, int nextTop) {

View selectedView = null;

// ListView getHeight也是这样计算的

int end = (mBottom - mTop);

if ((mGroupFlags & CLIP_TO_PADDING_MASK) == CLIP_TO_PADDING_MASK) {

end -= mListPadding.bottom;

}

// 初始化时pos = 0,如果item总数少于一屏幕,执行mItemCount - pos次

// 如果item多余一屏幕,执行end - nextTop次

while (nextTop < end && pos < mItemCount) {

// is this the selected item?

boolean selected = pos == mSelectedPosition;

// 获取Item View对象

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;

}

七、查看步骤4.4 ListView.makeAndAddView源码

[java] view
plaincopyprint?

// ListView都是通过此方法获取Item View

// 具体Item View如何复用,是否需要创建新的Item View都有此方法处理

private View makeAndAddView(int position, int y, boolean flow, int childrenLeft,

boolean selected) {

View child;

ListView的数据发生变化,肯定Item View之前已经创建好了,无需重新创建

if (!mDataChanged) {

// 当前position复用之前创建的视图

child = mRecycler.getActiveView(position);

if (child != null) {

// 对复用的View针对当前需要进行配置

setupChild(child, position, y, flow, childrenLeft, selected, true);

return child;

}

}

// 创建或者重用视图

child = obtainView(position, mIsScrap);

// This needs to be positioned and measured

setupChild(child, position, y, flow, childrenLeft, selected, mIsScrap[0]);

return child;

}

八 查看步骤4.5 ListView.setupChild源码

[java] view
plaincopyprint?

private void setupChild(View child, int position, int y, boolean flowDown, int childrenLeft,

boolean selected, boolean recycled) {

// 判断当前Item View是否选中状态

final boolean isSelected = selected && shouldShowSelector();

final boolean updateChildSelected = isSelected != child.isSelected();

final int mode = mTouchMode;

// 是否处于按下状态

final boolean isPressed = mode > TOUCH_MODE_DOWN && mode < TOUCH_MODE_SCROLL &&

mMotionPosition == position;

final boolean updateChildPressed = isPressed != child.isPressed();

// 是否需要重新measure与layout

final boolean needToMeasure = !recycled || updateChildSelected || child.isLayoutRequested();

// Respect layout params that are already in the view. Otherwise make some up...

// noinspection unchecked

AbsListView.LayoutParams p = (AbsListView.LayoutParams) child.getLayoutParams();

if (p == null) {

p = (AbsListView.LayoutParams) generateDefaultLayoutParams();

}

p.viewType = mAdapter.getItemViewType(position);

if ((recycled && !p.forceAdd) || (p.recycledHeaderFooter &&

p.viewType == AdapterView.ITEM_VIEW_TYPE_HEADER_OR_FOOTER)) {

attachViewToParent(child, flowDown ? -1 : 0, p);

} else {

p.forceAdd = false;

if (p.viewType == AdapterView.ITEM_VIEW_TYPE_HEADER_OR_FOOTER) {

p.recycledHeaderFooter = true;

}

// 向ListView(ViewGroup子类)添加当前Item View

addViewInLayout(child, flowDown ? -1 : 0, p, true);

}

// 更新选中状态

if (updateChildSelected) {

child.setSelected(isSelected);

}

// 更新按下状态

if (updateChildPressed) {

child.setPressed(isPressed);

}

if (mChoiceMode != CHOICE_MODE_NONE && mCheckStates != null) {

if (child instanceof Checkable) {

((Checkable) child).setChecked(mCheckStates.get(position));

} else if (getContext().getApplicationInfo().targetSdkVersion

>= android.os.Build.VERSION_CODES.HONEYCOMB) {

child.setActivated(mCheckStates.get(position));

}

}

if (needToMeasure) {

int childWidthSpec = ViewGroup.getChildMeasureSpec(mWidthMeasureSpec,

mListPadding.left + mListPadding.right, p.width);

int lpHeight = p.height;

int childHeightSpec;

if (lpHeight > 0) {

childHeightSpec = MeasureSpec.makeMeasureSpec(lpHeight, MeasureSpec.EXACTLY);

} else {

childHeightSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);

}

// 与普通视图的measure流程不同,ListView是在此处执行具体的当前Item View measure

child.measure(childWidthSpec, childHeightSpec);

} else {

cleanupLayoutState(child);

}

final int w = child.getMeasuredWidth();

final int h = child.getMeasuredHeight();

final int childTop = flowDown ? y : y - h;

if (needToMeasure) {

final int childRight = childrenLeft + w;

final int childBottom = childTop + h;

// 大小改变肯定位置也会发生变化,当前Item View重新进行layout

child.layout(childrenLeft, childTop, childRight, childBottom);

} else {

child.offsetLeftAndRight(childrenLeft - child.getLeft());

child.offsetTopAndBottom(childTop - child.getTop());

}

if (mCachingStarted && !child.isDrawingCacheEnabled()) {

child.setDrawingCacheEnabled(true);

}

if (recycled && (((AbsListView.LayoutParams)child.getLayoutParams()).scrappedFromPosition)

!= position) {

child.jumpDrawablesToCurrentState();

}

}

转载请注明原文地址:http://blog.csdn.net/love_world_/article/details/8547077
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: