Android ListView初始化简单分析

来源:互联网 发布:jeckins pipeline知乎 编辑:程序博客网 时间:2024/06/03 07:35



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

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




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

    private void initViewGroup() {        ......        // 初始化保存当前ViewGroup中所有View的数组        mChildren = new View[ARRAY_INITIAL_CAPACITY];        // 初始时其Child个数为0        mChildrenCount = 0;        ......    }



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


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

    @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的不同

    @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

    @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源码

// 从上向下在ListView中填充Item Viewprivate 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源码

    // 在参数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源码

    // 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源码

    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




原创粉丝点击