从应用角度看Android源码

来源:互联网 发布:淘宝达人开通 编辑:程序博客网 时间:2024/05/19 04:56

        最近用到了Adapter,以前只是知道怎么用,从能去研究他的原理,这次就想以baseadapter为例研究一下其原理,从设计模式角度看Android在adapter这块用到了典型的观察者模式,那就从这个点开始,看看他是怎样的一个观察者。一般我们会这样设置一个ListView的适配器

 list.setAdapter(adapter);
从这里开始,就开始adapter的神奇探索之旅

  public void setAdapter(ListAdapter adapter) {        if (mAdapter != null && mDataSetObserver != null) {            mAdapter.unregisterDataSetObserver(mDataSetObserver); //注销现有的观察者        }        resetList();        mRecycler.clear();        if (mHeaderViewInfos.size() > 0|| mFooterViewInfos.size() > 0) {            mAdapter = new HeaderViewListAdapter(mHeaderViewInfos, mFooterViewInfos, adapter);        } else {            mAdapter = adapter;        }        mOldSelectedPosition = INVALID_POSITION;        mOldSelectedRowId = INVALID_ROW_ID;        // AbsListView#setAdapter will update choice mode states.        super.setAdapter(adapter);        if (mAdapter != null) {            mAreAllItemsSelectable = mAdapter.areAllItemsEnabled();            mOldItemCount = mItemCount;            mItemCount = mAdapter.getCount();            checkFocus();            mDataSetObserver = new AdapterDataSetObserver();  //创建新的观察者            mAdapter.registerDataSetObserver(mDataSetObserver); //注册观察者            mRecycler.setViewTypeCount(mAdapter.getViewTypeCount());            int position;            if (mStackFromBottom) {                position = lookForSelectablePosition(mItemCount - 1, false);            } else {                position = lookForSelectablePosition(0, true);            }            setSelectedPositionInt(position);            setNextSelectedPositionInt(position);            if (mItemCount == 0) {                // Nothing selected                checkSelectionChanged();            }        } else {            mAreAllItemsSelectable = true;            checkFocus();            // Nothing selected            checkSelectionChanged();        }        requestLayout();  //请求布局    }


先看一下requestLayout();


   @Override    public void requestLayout() {        if (!mBlockLayoutRequests && !mInLayout) {            super.requestLayout();        }    }

调用了超类的requestLayout()

 public void requestLayout() {        if (mMeasureCache != null) mMeasureCache.clear();        if (mAttachInfo != null && mAttachInfo.mViewRequestingLayout == null) {            // Only trigger request-during-layout logic if this is the view requesting it,            // not the views in its parent hierarchy            ViewRootImpl viewRoot = getViewRootImpl();            if (viewRoot != null && viewRoot.isInLayout()) {                if (!viewRoot.requestLayoutDuringLayout(this)) {                    return;                }            }            mAttachInfo.mViewRequestingLayout = this;        }        mPrivateFlags |= PFLAG_FORCE_LAYOUT;        mPrivateFlags |= PFLAG_INVALIDATED;        if (mParent != null && !mParent.isLayoutRequested()) {            mParent.requestLayout();        }        if (mAttachInfo != null && mAttachInfo.mViewRequestingLayout == this) {            mAttachInfo.mViewRequestingLayout = null;        }    }
这里又会调用  mParent.requestLayout();mParent是什么呢,在View类里有这样一段代码

    void assignParent(ViewParent parent) {        if (mParent == null) {            mParent = parent;        } else if (parent == null) {            mParent = null;        } else {            throw new RuntimeException("view " + this + " being added, but"                    + " it already has a parent");        }    }

这个函数是ViewRootImpl调用setView(this)将自身做为参数。所以这个parent是一个ViewRootImpl的实例,至于这个ViewRootImpl是怎么回事不在这次的研究范围,暂且不去考究这个ViewRootImpl是怎么来的,看一下ViewRootImpl的requestLayout()函数。

    @Override    public void requestLayout() {        if (!mHandlingLayoutInLayoutRequest) {            checkThread();            mLayoutRequested = true;            scheduleTraversals();        }    }
继续往下找  scheduleTraversals()

    void scheduleTraversals() {        if (!mTraversalScheduled) {            mTraversalScheduled = true;            mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();            mChoreographer.postCallback(                    Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);            if (!mUnbufferedInputDispatch) {                scheduleConsumeBatchedInput();            }            notifyRendererOfFramePending();            pokeDrawLockIfNeeded();        }    }
这里面 mChoreographer.postCallback()只看名字就可以理解到这个调用将会发起一个callBack,暂且不看callBack的内容,继续看postCallBack()的实现


   public void postCallback(int callbackType, Runnable action, Object token) {        postCallbackDelayed(callbackType, action, token, 0);    }

    public void postCallbackDelayed(int callbackType,            Runnable action, Object token, long delayMillis) {        if (action == null) {            throw new IllegalArgumentException("action must not be null");        }        if (callbackType < 0 || callbackType > CALLBACK_LAST) {            throw new IllegalArgumentException("callbackType is invalid");        }        postCallbackDelayedInternal(callbackType, action, token, delayMillis);    }

    private void postCallbackDelayedInternal(int callbackType,            Object action, Object token, long delayMillis) {        if (DEBUG_FRAMES) {            Log.d(TAG, "PostCallback: type=" + callbackType                    + ", action=" + action + ", token=" + token                    + ", delayMillis=" + delayMillis);        }        synchronized (mLock) {            final long now = SystemClock.uptimeMillis();            final long dueTime = now + delayMillis;            mCallbackQueues[callbackType].addCallbackLocked(dueTime, action, token);            if (dueTime <= now) {                scheduleFrameLocked(now);            } else {                Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_CALLBACK, action);                msg.arg1 = callbackType;                msg.setAsynchronous(true);                mHandler.sendMessageAtTime(msg, dueTime);            }        }    }

跟到这里可以发现他吧callback放进message用handler里发送了出去,handler在之前已经学习过了,这样在handler里调用action的run()方法,在这之后再看看action的run()方法在做什么工作

 final class TraversalRunnable implements Runnable {        @Override        public void run() {            doTraversal();        }    }


    void doTraversal() {        if (mTraversalScheduled) {            mTraversalScheduled = false;            mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);            if (mProfile) {                Debug.startMethodTracing("ViewAncestor");            }            performTraversals();            if (mProfile) {                Debug.stopMethodTracing();                mProfile = false;            }        }    }


    private void performTraversals() {  略。。。。。。                   // Ask host how big it wants to be            windowSizeMayChange |= measureHierarchy(host, lp, res,                    desiredWindowWidth, desiredWindowHeight);        }       略。。。。。        if (!cancelDraw && !newSurface) {            if (!skipDraw || mReportNextDraw) {                if (mPendingTransitions != null && mPendingTransitions.size() > 0) {                    for (int i = 0; i < mPendingTransitions.size(); ++i) {                        mPendingTransitions.get(i).startChangingAnimations();                    }                    mPendingTransitions.clear();                }                performDraw();            }        }    }


在这里调用了 

measureHierarchy() 和  performDraw(); 依次看一下

    private boolean measureHierarchy(final View host, final WindowManager.LayoutParams lp,            final Resources res, final int desiredWindowWidth, final int desiredWindowHeight) {        if (lp.width == ViewGroup.LayoutParams.WRAP_CONTENT) {            if (baseSize != 0 && desiredWindowWidth > baseSize) {                childWidthMeasureSpec = getRootMeasureSpec(baseSize, lp.width);                childHeightMeasureSpec = getRootMeasureSpec(desiredWindowHeight, lp.height);                performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);                if ((host.getMeasuredWidthAndState()&View.MEASURED_STATE_TOO_SMALL) == 0) {                    goodMeasure = true;                } else {                    // Didn't fit in that size... try expanding a bit.                    baseSize = (baseSize+desiredWindowWidth)/2;                    childWidthMeasureSpec = getRootMeasureSpec(baseSize, lp.width);                    performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);                    if ((host.getMeasuredWidthAndState()&View.MEASURED_STATE_TOO_SMALL) == 0) {                        goodMeasure = true;                    }                }            }        }        if (!goodMeasure) {            childWidthMeasureSpec = getRootMeasureSpec(desiredWindowWidth, lp.width);            childHeightMeasureSpec = getRootMeasureSpec(desiredWindowHeight, lp.height);            performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);            if (mWidth != host.getMeasuredWidth() || mHeight != host.getMeasuredHeight()) {                windowSizeMayChange = true;            }        }                return windowSizeMayChange;    }


这里会调用performMeasure()方法

 private void performMeasure(int childWidthMeasureSpec, int childHeightMeasureSpec) {        Trace.traceBegin(Trace.TRACE_TAG_VIEW, "measure");        try {            mView.measure(childWidthMeasureSpec, childHeightMeasureSpec);        } finally {            Trace.traceEnd(Trace.TRACE_TAG_VIEW);        }    }


public final void measure(int widthMeasureSpec, int heightMeasureSpec) {        boolean optical = isLayoutModeOptical(this);        if (optical != isLayoutModeOptical(mParent)) {            Insets insets = getOpticalInsets();            int oWidth  = insets.left + insets.right;            int oHeight = insets.top  + insets.bottom;            widthMeasureSpec  = MeasureSpec.adjust(widthMeasureSpec,  optical ? -oWidth  : oWidth);            heightMeasureSpec = MeasureSpec.adjust(heightMeasureSpec, optical ? -oHeight : oHeight);        }        // Suppress sign extension for the low bytes        long key = (long) widthMeasureSpec << 32 | (long) heightMeasureSpec & 0xffffffffL;        if (mMeasureCache == null) mMeasureCache = new LongSparseLongArray(2);        final boolean forceLayout = (mPrivateFlags & PFLAG_FORCE_LAYOUT) == PFLAG_FORCE_LAYOUT;        final boolean isExactly = MeasureSpec.getMode(widthMeasureSpec) == MeasureSpec.EXACTLY &&                MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.EXACTLY;        final boolean matchingSize = isExactly &&                getMeasuredWidth() == MeasureSpec.getSize(widthMeasureSpec) &&                getMeasuredHeight() == MeasureSpec.getSize(heightMeasureSpec);        if (forceLayout || !matchingSize &&                (widthMeasureSpec != mOldWidthMeasureSpec ||                        heightMeasureSpec != mOldHeightMeasureSpec)) {            // first clears the measured dimension flag            mPrivateFlags &= ~PFLAG_MEASURED_DIMENSION_SET;            resolveRtlPropertiesIfNeeded();            int cacheIndex = forceLayout ? -1 : mMeasureCache.indexOfKey(key);            if (cacheIndex < 0 || sIgnoreMeasureCache) {                // measure ourselves, this should set the measured dimension flag back                onMeasure(widthMeasureSpec, heightMeasureSpec);                mPrivateFlags3 &= ~PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT;            } else {                long value = mMeasureCache.valueAt(cacheIndex);                // Casting a long to int drops the high 32 bits, no mask needed                setMeasuredDimensionRaw((int) (value >> 32), (int) value);                mPrivateFlags3 |= PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT;            }            // flag not set, setMeasuredDimension() was not invoked, we raise            // an exception to warn the developer            if ((mPrivateFlags & PFLAG_MEASURED_DIMENSION_SET) != PFLAG_MEASURED_DIMENSION_SET) {                throw new IllegalStateException("onMeasure() did not set the"                        + " measured dimension by calling"                        + " setMeasuredDimension()");            }            mPrivateFlags |= PFLAG_LAYOUT_REQUIRED;        }        mOldWidthMeasureSpec = widthMeasureSpec;        mOldHeightMeasureSpec = heightMeasureSpec;        mMeasureCache.put(key, ((long) mMeasuredWidth) << 32 |                (long) mMeasuredHeight & 0xffffffffL); // suppress sign extension    }
这里的public final void measure(int widthMeasureSpec, int heightMeasureSpec)中的final意味着这个函数不会被子类重写,这能在这个类中实现。函数实现中又调用了view的onMeasure().其实这里调用的就是ListView中的onMeasure()





    private void performDraw() {           略。。。。        try {            draw(fullRedrawNeeded);        } finally {            mIsDrawing = false;            Trace.traceEnd(Trace.TRACE_TAG_VIEW);        }       略。。。。              }    }


   private void draw(boolean fullRedrawNeeded) {        略。。。。                        if (!drawSoftware(surface, mAttachInfo, xOffset, yOffset, scalingRequired, dirty)) {                    return;                }        略。。。。    }

 private boolean drawSoftware(Surface surface, AttachInfo attachInfo, int xoff, int yoff,            boolean scalingRequired, Rect dirty) {        final Canvas canvas;        private void draw(boolean fullRedrawNeeded) {            略。。。。        try {                canvas.translate(-xoff, -yoff);                if (mTranslator != null) {                    mTranslator.translateCanvas(canvas);                }                canvas.setScreenDensity(scalingRequired ? mNoncompatDensity : 0);                attachInfo.mSetIgnoreDirtyState = false;                mView.draw(canvas);                drawAccessibilityFocusedDrawableIfNeeded(canvas);            }           略。。。。    return true;    }

这里调用的View的draw()函数,然后就会开始绘制了。

 public void draw(Canvas canvas) {        final int privateFlags = mPrivateFlags;        final boolean dirtyOpaque = (privateFlags & PFLAG_DIRTY_MASK) == PFLAG_DIRTY_OPAQUE &&                (mAttachInfo == null || !mAttachInfo.mIgnoreDirtyState);        mPrivateFlags = (privateFlags & ~PFLAG_DIRTY_MASK) | PFLAG_DRAWN;              int saveCount;        if (!dirtyOpaque) {            drawBackground(canvas);        }        final int viewFlags = mViewFlags;        boolean horizontalEdges = (viewFlags & FADING_EDGE_HORIZONTAL) != 0;        boolean verticalEdges = (viewFlags & FADING_EDGE_VERTICAL) != 0;        if (!verticalEdges && !horizontalEdges) {            if (!dirtyOpaque) onDraw(canvas);            dispatchDraw(canvas);            if (mOverlay != null && !mOverlay.isEmpty()) {                mOverlay.getOverlayView().dispatchDraw(canvas);            }            onDrawForeground(canvas);            return;        }




原创粉丝点击